10.2. Операции с регулярными выражениями
Глава 10 Работа со строками
🕛 02.11.2006, 15:58
В данной главе неоднократно упоминались операции с регулярными выражениями, такие как поиск по образцу. Основными среди них являются: операция поиска т//, операция замены s/// и операция транслитерации tr///.10.2.1. Операция поиска
m/PATTERN/cgimosx
Операция поиска HI/PATTERN/ осуществляет поиск образца PATTERN. Результатом операции является значение 1 (ИСТИНА) или пустая строка"
(ЛОЖЬ). По умолчанию поиск осуществляется в строке, содержащейся в специальной переменной $_. Можно назначить другую строку для поиска в ней заданного образца при помощи операций связывания =~ или ! ~:
$var =~ m/PATTERN/cgimosx
В результате последней операции поиск образца PATTERN будет осуществляться в строке, задаваемой переменной $var. Если в правой части операции связывания стоит операция поиска т//, то в левой части может находиться не обязательно переменная, а любое строковое выражение.
Операция ! ~ отличается от операции =~ тем, что возвращает противоположное логическое значение. Например, в результате поиска в строке "aaabbbccc" образца /Ь+/Г
$s="aaabbbccc" =~ m/b+/; $s="aaabbbccc" !~ m/b+/;,
в обоих случаях будет найден фрагмент ььь. Но в первом случае возвращаемое значение, сохраненное в переменной $s, будет равно 1 (ИСТИНА), а во втором случае - пустой строке " (ЛОЖЬ).
Образец PATTERN может содержать переменные, значения которых подставляются при каждом выполнении поиска по данному образцу.
Флаги cgimosx модифицируют выполнение операции поиска. Флаги imsx имеют тот же смысл, что и в рассмотренном выше случае конструкции расширенного регулярного выражения (?imsx-imsx) .
i - поиск без учета регистра;
m - трактуется как мульти-строка, состоящая из нескольких строк, разделенных символом новой;
s - строка трактуется как одна строка, в этом случае метасимволу "." со-, ответствует любой одиночный символ, включая символ новой строки;
х - разрешается использовать в образцах пробелы и комментарии.
стальные флаги выполняют следующие функции.
g - Задает глобальный поиск образца в заданной строке. Это означает, что будут найдены все фрагменты текста, удовлетворяющие образцу, а не только первый из них, как имеет место по умолчанию. Возвращаемое значение зависит от контекста. Если в составе образца имеются подоб-разцы, заключенные в скобки (), то в контексте массива для каждого заключенного в скобки подобразца возвращается список всех найденных фрагментов. Если в составе образца нет подобразцов, заключенных в скобки, то в контексте массива возвращается список всех найденных фрагментов, удовлетворяющих образцу. В скалярном контексте каждая операция m//g осуществляет поиск следующего фрагмента, удовлетворяющего образцу, возвращая значение 1 (ИСТИНА), если он найден, и пустую строку ", если не найден. Позиция строки, в которой завершился последний поиск образца при установленном флаге g, может быть получена при помощи встроенной функции роз о (см. ниже). Обычно при неудачном поиске начальная позиция поиска восстанавливается в начало строки. Флаг с отменяет восстановление начальной позиции поиска при неудачном поиске образца.
Рассмотрим следующий скрипт.
$str="abaabbaaabbbaaaabbbb";
tt контекст массива, нет подобразцов в скобках
@result=$str =~m/a+b+/g;
print "контекст массива, нет конструкций в скобках:\п";
print "\@result=@result\n";
# контекст массива, есть конструкции в скобках, задающие обратные ссылки
9result=$Str =~m/(a+)(b+)/g;
print "контекст массива, есть конструкции в скобках:\п";
print "\@result=@result\n";
# скалярный контекст
print "скалярный контекст:\п";
while ($result=$str =~m/(a+)(b+)/g) {
print "result=$result, current match is $&, position=",pos($str),"\n"; }
Результатом его выполнения будет вывод:
контекст массива, нет конструкций в скобках:
@result=ab aabb aaabbb aaaabbbb
контекст массива, есть конструкции в скобках:
@result=a b aa bb ааа bbb aaaa bbbb
скалярный контекст:
result=l, current match is ab, position=2
result=l, current match is aabb, position=6
result=l, current match is 'aaabbb, position=12
result=l, current match is aaaabbbb, position=20
HI с - Используется совместно с флагом g. Отменяет восстановление начальной позиции поиска при неудачном поиске образца.
Рассмотрим скрипт
$str="abaabbaaabbbaaaabbbb";
while ($result=$str =~m/(a+)(b+)/g) {
print "result=$result, current match is $&, position=",pos($str),"\n";
} - print "last position=", pos($str), "\n";
Здесь поиск образца /а+ь+/ в строке $str осуществляется в цикле до первой неудачи. При последнем (неудачном) поиске начальная позиция поиска по умолчанию устанавливается в начало строки, в этом случае вывод имеет вид:
result=l, current match is ab, position=2 result=l, current match is aabb, position=6 result=l, current match is aaabbb, position=12 result=l, current match is aaaabbbb, position=20 last position=
Если глобальный поиск осуществлять при установленном флаге с:
while ($result=$str =~m/ (a+) (b+)/gc) {
то при последнем неудачном поиске начальная позиция поиска не переустанавливается. Вывод имеет вид:
result=l, current match is abr position=2 result=l, current match is aabb, position=6 result=l, current match is aaabbb, position=12 result=l, current match is aaaabbbb, position=20 last position=20
При задании образца для глобального поиска m//g можно использовать ме-тапоследовательность \с, представляющую точку, в которой закончился последний поиск m//g. Например, в результате выполнения скрипта .
^^х
$str="l) abc 2) aabbcc 3) aaabbbccc 4) aaaabbbbcccc";
$str=~m/3\)\s+/g; \
! $str=~m/\Ga+/; ,'
сначала по образцу будет найден фрагмент "3)", а затем фрагмент, удовлетворяющий образцу /а+/ и расположенный сразу за точкой, в которой завершился последний поиск. Этим фрагментом является "ааа".
По- Значения переменных, входящих в состав образца PATTERN, подставляются только один раз, а не при каждом поиске по данному образцу. Рассмотрим, например, следующий скрипт:
@pattnlist=("a+", "Ы-", "с+", "d+") ; foreach $pattn (@pattnlist) (
$line = <STDIN>; $line =~ m/$pattn/o;
print "pattn=$pattn \$&= $&\n"; }
Массив gpattniist содержит список образцов "a+", "ь+", "с+" и "d+". В цикле по элементам этого списка в переменную $iine считывается очередная строка из стандартного ввода. В ней осуществляется поиск по образцу, совпадающему с текущим элементом списка. Поскольку использован флаг о, подстановка значений в образце /$pattn/ будет осуществлена один раз за время жизни данной Peri-программы, т. е. в качестве образца на каждом шаге цикла будет использовано выражение "а+". Если операцию поиска осуществлять без флага о:
$line =~ m/$pattn/,
то в качестве образца будут последовательно использованы все элементы списка "а+", нь+", "с+" и "d+".
В качестве символов-ограничителей для выделения образца можно использовать любую пару символов, не являющихся цифрой, буквой или пробельным символом. Если в качестве ограничителя используется символ "/", то литеру m в обозначении операции можно опустить и использовать упрощенную форму /PATTERN/ BMeCTO m/PATTERN/.
Если в качестве ограничителя используется одинарная кавычка ', то подстановка значений переменных внутри образца не производится.
Если в качестве ограничителя используется символ "?": ?PATTERN?, то при применении операции поиска находится только одно соответствие. Например, в результате выполнения скрипта
$str="abaabbaaabbbaaaabbbb";
while ($result = $str =~ m?a+b+?g) (
print "result=$result, current match is $&, position=", pos($str),"\n";
}
будет найдено только первое соответствие образцу:
result=l, current match is ab, position=2
10.2.2. Операция замены
s/PATTERN/REPLACEMENT/egimosx
Операция замены S/PATTERN/REPLACEMENT/ осуществляет поиск образца PATTERN и, в случае успеха, замену найденного фрагмента текстом REPLACEMENT. Возвращаемым значением является число сделанных замен или пустая строка (ЛОЖЬ), если замен не былоТПо умолчанию поиск и замена осуществляются в специальной переменной $_. Ее можно заменить другой строкой при помощи операций связывания =~ или ! ~:
$var =~ s/PATTERN/REPLACEMENT/egimosx
Флаг $ задает глобальную замену всех фрагментов, удовлетворяющих образцу PATTERN,TeKCTOM REPLACEMENT.
Флаг е означает, что заменяющий текст REPLACEMENT следует рассматривать как Peri-выражение, которое надо предварительно вычислить. Например, в результате выполнения скрипта
$str="abaabbaaabbbaaaabbbb"; $result=$str =~s[ (a+b+)]<length($l)>ge; print "result=$result new str=$str\n";
будет выведено число сделанных замен $ result и новое значение строки $str, в которой каждый найденный фрагмент, соответствующий образцу [а+ь+], заменен числом, равным его длине:
result=4 new str=2468
Флаги imosx имеют тот же смысл, что для операции поиска т//.
Так же, как и в операции замены, в качестве ограничителей для выделения образца можно использовать любую пару символов, не являющихся цифрой, буквой или пробельным символом. Можно использовать различные ограничители для выделения образца и замещающего текста, например,
s(pattern)<replacement>.
10.2.3. Операция транслитерации
tr/SEARCHLIST/REPLACEMENTLIST/cds
Преобразует каждый символ из списка поиска SEARCHLIST в соответствующий символ из списка замены REPLACEMENTLIST и возвращает число преобразованных символов. По умолчанию преобразования осуществляются в строке, задаваемой переменной $_. Как и в рассмотренных выше операциях поиска и замены, при помощи операций связывания =~ и ! ~ можно задать для преобразования строку, отличную от принятой по умолчанию
$str =~ tr/SEARCHLIST/REPLACEMENTLIST/cds
Списки SEARCHLIST и REPLACEMENTLIST задаются перечислением символов, могут содержать диапазоны - два символа, соединенных знаком "-", и иметь собственные символы-ограничители, например, tr(a-j) /0-9/. Операция tr/// имеет синонимичную форму, используемую в потоковом редакторе sed:
y/SEARCHLIST/REPLACEMENTLIST/cds
Флаги cds имеют следующий смысл.
с - вместо списка поиска SEARCHLIST использовать его дополнение до основного множества символов (обычно расширенное множество ASCII).
d - удалить все символы, входящие в список поиска SEARCHLIST, для которых нет соответствия в списке замены REPLACEMENTLIST. Если флаг d не установлен и список замены REPLACEMENTLIST короче, чем список поиска SEARCHLIST, то вместо недостающих символов в списке замены используется последний символ этого списка. Если список замены пуст, то символы из списка поиска SEARCHLIST преобразуются сами в себя, что удобно использовать для подсчета числа символов в некотором классе. П s - все последовательности символов, которые были преобразованы в один и тот же символ, заменяются одним экземпляром этого символа.
$str =~ tr/A-Z/a-z/; # преобразование прописных букв в строчные $count=$str=~tr/\000//c; # подсчет числа символов в строке $str $str =~ tr/\200-\377/ /cs; # любая последовательность символов
с ASCII-кодами от 128 до 255 преобразуется
в единственный пробел
Следующий скрипт преобразует русский текст в DOS-кодировке 866, содержащийся в файле "866.txt", в русский текст в Windows-кодировке 1251, и записывает преобразованный текст в файл "1251. txt".
open(IN866, "866.txt"); open(OUT1251,">125I.txt"); while ($line=<IN866>) { .
$line=~tr/\200-\257\340-\361/\300-\377\250\270/; print OUT1251 $line;
>
close(IN866); close(OUT1251);
10.2.4. Операция заключения в кавычки qr//
qr/STRING/imosx
Операция qr// по своему синтаксису похожа^наГдругие операции заключения в кавычки, такие как q//, qq//, qx//, qw//. Она обсуждается в данном разделе, так как имеет непосредственное отношение к регулярным выражениям. Регулярное выражение, содержащее переменные, метасимволы, мета-последовательности, расширенный синтаксис, перед использованием должно быть обработано компилятором. Операция qr// осуществляет предварительную компиляцию регулярного выражения STRING, преобразуя его в некоторое внутреннее представление, с тем, чтобы сохранить скомпилированное регулярное выражение в переменной, которую затем можно использовать без повторной компиляции самостоятельно или в составе других регулярных выражений.
Преимущества от применения операции qr// проявляются, например, в следующей ситуации. Допустим, что мы собираемся многократно использовать в качестве образца достаточно сложное регулярное выражение, например, /Л([Л ]*) *([Л ]*)/. Его можно использовать непосредственно в операции сопоставления с образцом
if ($line =~ /Л(Г ]*) *([Л ]*)/) {...},
или сохранить в переменной $pattern=ll/4 ([Л ]*) *([А ]*) и обращаться к переменной:
if ($line =~ /$pattern/) (...},
В обоих случаях регулярное выражение при каждом обращении обрабатывается компилятором, что при многократном использовании увеличивает время выполнения. Если сохранить образец при помощи операции qr//:
$pattn = qr/~(r ]*) *<Г ]*)/,
то переменная $pattn будет содержать откомпилированное регулярное выражение, которое можно неоднократно использовать без дополнительной компиляции.
Флаги imosx имеют тот же смысл, что и в операции замены т//. Например, в следующем тексте операция qr// применяется с флагами ох:
$s="aA!Bb2cC3Dd45Ee";
@pattns=("\\d+ # последовательность цифр",
"[A-Z]+ t последовательность прописных букв", "[a-z]+ # последовательность строчных букв"); foreach $pattn Opattns) { my $pattern=qr/$pattn/ox; while ($s=~/$pattern/g) { $p=$p.$&; . } } print "s=$s p=$p\n";
В данном примере определен массив @pattns, состоящий из регулярных выражений. В цикле по элементам массива проверяется наличие в заданной строке $з фрагмента, соответствующего текущему образцу. Найденный фрагмент добавляется в конец строки $р. Флаг х в операции qr// позволяет использовать образцы в том виде, в каком они хранятся в массиве - с пробелами и комментариями. Если в операции qr// флаг о не установлен, то в результате выполнения скрипта строка $р будет состоять из символов строки $s, расположенных в следующем порядке: сначала все цифры, затем все прописные буквы, затем все строчные буквы. Если, как в данном ^тексте, флаг о установлен, то в операции $pattern=qr/$pattn/ox подстановка переменной $pattn произойдет только один раз, и строка $s будет три раза проверяться на наличие фрагмента, удовлетворяющего первому образцу $pattns. В результате строка $р будет состоять только из цифр, входящих в строку $s, повторенных три раза.