Содержание:
Назначение
Скрипт предназначен для в основном для пакетных замен текстовом файле.
Варианты командной строки:
replacer_v2_0_1_4.pl -rd list input.txt output.txt
replacer_v2_0_1_4.pl -rt list input.txt output.txt
replacer_v2_0_1_4.pl -rdn list input.txt output.txt
replacer_v2_0_1_4.pl -rtn list input.txt output.txt
replacer_v2_0_1_4.pl -ra list -[A-Za-z]{1,10} input.txt output.txt
replacer_v2_0_1_4.pl -rs list -[A-Za-z]{1,10} input.txt output.txt
replacer_v2_0_1_4.pl -t input.txt output.txt
replacer_v2_0_1_4.pl -f list
1)replacer_v2_0_1_4.pl -rd list input.txt output.txt
Сделать замены в файле имеющем словарную структуру (-rd - replace dictionary) используя список замен (list).
2)replacer_v2_0_1_4.pl -rt list input.txt output.txt
Сделать замены в файле не имеющем словарную структуру (-rt - replace text) используя список (list).
3)replacer_v2_0_1_4.pl -rdn list input.txt output.txt
Сделать замены в файле имеющем словарную структуру (-rdn - replace dictionary \n) используя список замен (list),
но без автоматического добавления при записи управляющих символов \x0D \x0A (\n).
4)replacer_v2_0_1_4.pl -rtn list input.txt output.txt
Сделать замены в файле не имеющем словарную структуру (-rtn - replace text \n) используя список (list),
но без автоматического добавления при записи управляющих символов \x0D \x0A (\n).
5)replacer_v2_0_1_4.pl -ra list -[A-Za-z]{1,10} input.txt output.txt
-ra - replace & angle (brackets)
Произвести замены между указанными в третьем параметре командной строки HTML тэгами.
Этот режим может использоваться только если input.txt имеет словарную структуру.
<example>abcd</example> - replacer_v2_0_1_4.pl -ra list -example input.txt output.txt
<example class=name>abcd</example> - работать не будет.
6)replacer_v2_0_1_4.pl -rs list -[A-Za-z]{1,10} input.txt output.txt
-rs - replace & square (brackets)
Произвести замены между указанными в третьем параметре командной строки DSL тэгами.
Этот режим может использоваться только если input.txt имеет словарную структуру.
[p]abcd[/p] - replacer_v2_0_1_4.pl -rs list -p input.txt output.txt
[c red]abcd[/c] - работать не будет.
7)replacer_v2_0_1_4.pl -t input.txt output.txt
Получить список HTML тэгов.
input.txt обрабатывается построчно.
Соответственно тэги которые начинаются на одной строке, а заканчиваются на другой в список не попадут.
8)replacer_v2_0_1_4.pl -f list
Про это будет сказано в разделе "Использование perl кода в списке замен."
Файл имеющий СЛОВАРНУЮ СТРУКТУРУ - это файл имеющий словарную структуру - это файл в котором заглавные слова пишутся с первой позиции новой строки, а начиная со следующей строки после заголовка записывается тело статьи, причем каждая строка в нем должна отступать от первой позиции хотя бы на один пробел или табуляцию. Тело статьи простирается до заголовка следующей статьи (признаком его является символ в первой позиции, отличный от пробела или табуляции) или до конца файла. Между телом одной и заголовком следующей статьи для удобства чтения исходного текста могут быть вставлены одна или несколько пустых строк.
Форматы записей в списке замен
1)Простые замены.
^(.+?)[\t\x20]+\|[\t\x20]+(.*)$
Пример:
a | b a |
2)Замены с использованием регулярных выражений.
^(.+?)[\t\x20]+\|([i]{0,1})\|[\t\x20]+(.*)$
Пример:
(\d) || $1 \[i\] || ^(<[a-z]+>)$ |i| $1
Ниже список специальных символов, которые в регулярных выражениях следует обязательно экранировать для превращения их в литеральные (если требуется):
[]\^$.|?*+()
В правой части это можно не делать.
Пример:
(\[\]\\\^\$\.\|\?\*\+\(\)) || []\^$.|?*+()$1
Символ ' и " можно не экранировать в обоих частях.
Строки начинающиеся с символа # скриптом игнорируются
Если требуется что-то заменить начинающиеся с этого символа, то можно использовать подобное выражение:
\# || a
Символ табуляции и пробел используются для разделения левой и правой части,
поэтому если нужно заменить что-то заканчивающиеся пробелом или символом табуляции,
то нужно использовать выражения следующего вида:
(dog ) || pig (dog\x20) || pig
Если нужно заменить что-то на что-то начинающиеся с символа табуляции или пробела:
pig || \tdog
Возможные ошибки
- входной файл имеет кодировку UTF-16 или UTF-32 (Unicode)
- недопустимый формат командной строки или недопустимое значение какого-либо параметра.
Пример сообщения об ошибке:
"Malformed UTF-8 character (fatal) at C:\Temp\replacer_v2_0_1_4.pl line 41, line 2"
Данная ошибка была вызвана тем, что список замен содержал кириллические символы в кодировке windows-1251.
Аварийная остановка - Ctrl+C
Для понимания
Во что превращается список замен можно увидеть запустив скрипт с такой командной строкой:
replacer_v2_0_1_4.pl -f list
Результат будет записан в файл func.txt
Допустим мы имеем список замен, который содержит следующее:
dog | pig ^<([uib])>$ |i| \[$1\]
Выполняем replacer_v2_0_1_4.pl -f list
Результат:
package LIST020009121{ sub SUBR920909421::replace{ my $s = shift; $s =~ s/dog/pig/g; $s =~ s/^<([uib])>$/\[$1\]/gis; return $s; } }
Неправильно:
if (($a == $b) || ($c == $d))
Правильно:
if (($a == $b)||($c == $d))
if (($a == $b) or ($c == $d))
Выражения полученные из записей второго типа (с использованием регулярных выражений) содержат модификатор "s".
s - благодаря этому модификатору входной текст воспринимается как одна строка. При этом метасимвол ".'' совпадает с любым символом, если же этот модификатор выключен, то он не совпадает с разделителями строк.
g - добавляется в обоих случаях.
i - опционально.
В списке замен процедурам можно давать любые имена, в том числе и "replace".
Имена пакетов которые уже используются в скрипте:
LIST020009121
SUBR920909421
MAIN826001181
ReplaceList
undef
Если процедура SUBR920909421::replace вернет пустую строку ($s = ''), то в выходном файле будет сделана такая запись: "\n". Т. е. в файле появится пустая строка.
В выходной файл вообще ничего не будет записано если SUBR920909421::replace вернет undef ($s = undef).
Переменные
Пример №1:
$anyname::number++; print $anyname::number;
Результат будет таким:
123456789... каждый вызов процедуры SUBR920909421::replace (сделанной из списка замен) увеличивает
значение переменной $anyname::number.
Пример №2:
my $number; $number++; print $number;
Результат:
111111111...
Модификатор "s"
Если результат не соответствует ожиданиям, то возможно это связано с отсутствием этого модификатора, там где это необходимо.
Пример №1:
$s = "dog\n\t a domesticated canine mammal..."; if ($s =~ /^(.*)$/){print $1}
Результат: ""
Пример №2:
$s = "dog\n\t a domesticated canine mammal..."; if ($s =~ /^(.*)$/s){print $1}
Результат: "dog\n\t a domesticated canine mammal..."
Дополнительные возможности
1)Если необходимо что-то скинуть в выходной файл только после того как будет обработан весь входной файл, то нужно использовать пакет "RaplaceList" и процедуру "onexit" которая возвращает массив. В самом конце работы скрипта делается проверка на наличие данной процедуры, если такая обнаружится, то содержимое полученного массива записывается в выходной файл без добавления разделителей строк в конце, это обязанность пользователя.
Пример использования:
while ($s =~ /^.*?(\&\#[\d]+\;|\&\#[\d]+|\&[a-z]+\;)(.*)$/s){
$anyname::table{"$1\n"} = '';
$s = $2;
}
#чтобы не было пустых строк
$s = undef;
sub ReplaceList::onexit{
my @k = keys %anyname::table;
return @k;
}
Возможный результат:
æ å ø
2)Для остановки скрипта с выводом сообщения на экран и записью его в файл error.log
достаточно инициализировать специальную переменную "errormessage" из пакета "ReplaceList"
Пример использования:
if ($ARGV[0] ne '-rt') { $ReplaceList::errormessage = "Use \'-rtn\' instead of \'$ARGV[0]\'\n"; }
Дополнительные примеры
Пример №1:
Изменить регистр заголовков
if ($s =~ /^([^\x20\t][^\n]+)(\n.*)$/s) { my $hw = lc($1); $s = "$hw$2"; }
Пример №2:
Получить спискок всех слов
while ($s =~ /^.*?([\p{L}]{1,}[\-\'\p{L}]+[\p{L}]{1,}|[\p{L}]{2,})(.*)$/s)
{
$anyname::table{"$1\n"} = '';
$s = $2;
}
#чтобы не было пустых строк
$s = undef;
sub ReplaceList::onexit{
my @k1 = keys %anyname::table;
my @k2 = sort { $a cmp $b } @k1;
return @k2;
}
Пример №3:
Вытащить из файла все HTML сущности и сделать список замен
while ($s =~ /^.*?(\&\#[\d]+\;|\&\#[\d]+|\&[a-z]+\;)(.*)$/s){
$anyname::table{"$1"} = '';
$s = $2;
}
#чтобы не было пустых строк
$s = undef;
sub ReplaceList::onexit{
my @k1 = keys %anyname::table;
use HTML::Entities();
my @k2;
foreach(@k1)
{
my $t = HTML::Entities::decode($_);
push @k2, "$_\t\|\t$t\n";
}
return @k2;
}
Возможный результат:
å | å æ | æ æ | æ ø | ø
Пример №4:
Произвести замену между указанными тэгами
sub replacelist{ my $s = shift; d | 1 o | 2 m | 4 return $s; } my $ot = '[p]'; my $ct = '[/p]'; $s =~ s/,/\&\#44;/g; $s =~ s/(\Q$ot\E)/,$1/gi; $s =~ s/(\Q$ct\E)/$1,/gi; my @temparr = split(/,/, $s); for (my $i = 0; $i < @temparr; $i++) { if ($temparr[$i] =~ /^\Q$ot\E(.+)\Q$ct\E$/is) { my $between = $1; $between =~ s/\&\#44;/,/g; $between = replacelist($between); $temparr[$i] = "$ot$between$ct"; $temparr[$i] =~ s/\&\#44;/,/g; } } $s = join("", @temparr); @temparr = (); $s =~ s/\&\#44;/,/g;
Пример №5:
Получить список всех символов и фрагментов которые встречаются между указанными тэгами
sub replacelist{ my $s = shift; #удаляем другие тэги \[(sup|sub|i|b|u)\] |i| return $s } my $ot = '[p]'; my $ct = '[/p]'; $s =~ s/,/\&\#44;/g; $s =~ s/(\Q$ot\E)/,$1/gi; $s =~ s/(\Q$ct\E)/$1,/gi; my @temparr = split(/,/, $s); foreach (@temparr) { if ($_ =~ /^\Q$ot\E(.+)\Q$ct\E$/is) { my $between = $1; $between =~ s/\&\#44;/,/g; $between = replacelist($between); $hash::table1{$between} = ''; my @char_array = split(//, $between); foreach(@char_array) { $hash::table2{$_} = ''; } } } #чтобы не было пустых строк $s = undef; sub ReplaceList::onexit{ my @r; my @k1 = keys %hash::table2; my @k2 = sort { $a cmp $b } @k1; @r = @k2; push @r, "\n\nFRAGMENTS:\n"; @k1 = keys %hash::table1; my @k2 = sort { $a cmp $b } @k1; foreach(@k2) { push @r, "$_\n"; } if (@r > 0){$r[0] = "SYMBOLS:\n$r[0]"}; return @r; }
Возможный результат:
SYMBOLS: acdgiopt FRAGMENTS: cat dog pig
Пример №6:
Получить список всех символов встречающихся в каком-либо текстовом файле.
#COMMAND LINE:
#replacer_v2_0_1_4.pl -rt list.txt input.txt output.txt
#------------------------------------------------------
sub codepoint_hex {
if (my $char = shift) {
return sprintf '%2.2x', unpack('U0U*', $char);
}
}
sub pad {
my $str = shift;
while (length $str < 4){
$str = "0$str";
}
return "0x$str";
}
my @arr = split(//, $s);
foreach(@arr){
$pack::hash{"$_"}='';
}
$s=undef;
sub ReplaceList::onexit{
use Encode;
use charnames ':full';
my @k = keys %pack::hash;
my @sorted = sort{$a cmp $b} @k;
foreach my $r (@sorted)
{
my $cp = pad(codepoint_hex($r));
my $oc = encode("UTF-8", $r);
my $h = unpack("H*", $oc);
my $name = charnames::viacode($cp);
$r = "$r\t$cp\t$h\t$name\n";
}
return @sorted;
}
Возможный результат:
÷ 0x00f7 c3b7 DIVISION SIGN ø 0x00f8 c3b8 LATIN SMALL LETTER O WITH STROKE û 0x00fb c3bb LATIN SMALL LETTER U WITH CIRCUMFLEX ü 0x00fc c3bc LATIN SMALL LETTER U WITH DIAERESIS ą 0x0105 c485 LATIN SMALL LETTER A WITH OGONEK Ć 0x0106 c486 LATIN CAPITAL LETTER C WITH ACUTE ć 0x0107 c487 LATIN SMALL LETTER C WITH ACUTE ę 0x0119 c499 LATIN SMALL LETTER E WITH OGONEK Ł 0x0141 c581 LATIN CAPITAL LETTER L WITH STROKE ł 0x0142 c582 LATIN SMALL LETTER L WITH STROKE ń 0x0144 c584 LATIN SMALL LETTER N WITH ACUTE ŋ 0x014b c58b LATIN SMALL LETTER ENG œ 0x0153 c593 LATIN SMALL LIGATURE OE
На Windows скрипт будет удобнее запускать если создать batch файл с таким содержанием:
@ECHO OFF if "%1" == "-h" ( start firefox.exe полный_путь\readme.htm ) ELSE ( полный_путь\replacer_v2_0_1_4.pl %* )
Этот файл нужно поместить в папку C:\Windows\System32\ и заменить "полный_путь" на реальный.
Можно также заменить "firefox.exe" на другой браузер.
После этого скрипт можно будет запускать из любого места используя, например, такую командную строку:
repl -rt list input.txt output.txt
Вызов справки: repl -h
Вариант для Linux:
function replacer() { clear if [[ $# -eq 1 ]] && [[ "$1" -eq "-h" ]]; then (firefox полный_путь/readme.htm >/dev/null 2>&1 &) else perl полный_путь/replacer_v2_0_1_4.pl "$@" echo '' echo "$(tput sgr 0)$(tput setaf 3)Press Enter to return$(tput sgr 0)" read input fi } alias repl=replacer
Вышеприведенный код нужно добавить в .bashrc файл.