Операторы поиска и замены

До сих пор здесь обсуждался язык регулярных выражений вне всякой связи с каким-либо языком программирования. Пришло время обсудить, как пользоваться возможностями регулярных выражений в программах на Perl.

Для поиска по шаблону в языке Perl предусмотрен оператор поиска m/⋯/. Вместо многоточия следует поместить шаблон. Текст, в котором производится поиск, должен находиться в переменной по умолчанию $_. Тогда оператор m/⋯/ возвращает логическое значение, истинное при успешном поиске, и ложное в противном случае. Если шаблон содержит группы захвата, то в качестве побочного эффекта при успешном поиске получат свои значения групповые переменные $1, $2, … — те самые буферы захвата, о которых шла речь в разделе «Захват».

Следующий фрагмент кода проверяет, содержит ли переменная $_ десятичную запись целого числа (как минимум одна десятичная цифра, которой, возможно, предшествует знак минуса):

Perl
if(m/^\-?\d+$/) { print "число\n"; } else { print "не число\n"; }

или

Perl
print(m/^\-?\d+$/? '': 'не ', "число\n");

Мы видим, что знаки косой (слэши) черты служат ограничителями, внутри которых заключён шаблон. Это, конечно, означает, что просто так эти знаки не получится использовать в шаблоне. Не нужно быть очень умным, чтобы сообразить, как обойти эту трудность. Разумеется, следует ставить бэкслэши перед слэшами. К примеру, если в переменной $_ находится полное имя файла, проверка того, лежит ли файл в директории /usr/bin, будет выглядеть так:

Perl
if(m/^\/usr\/bin\//) { print "лежит"; } else { print "не лежит"; }

Если часто приходится обрабатывать имена файлов и директорий с помощью регулярных выражений, удобно использовать альтернативные формы оператора поиска с другими ограничителями: m#⋯#, m!⋯!, m+⋯+, m(⋯), m[⋯]. Сравните: m/^\/usr\/bin\// и m#^/usr/bin/#. Тогда, помещая в шаблон выбранный символ ограничителя (кроме скобок), нужно позаботиться о его защите и вставить перед ним бэкслэш. Со скобками в качестве ограничителей такой проблемы нет (почему?). Программисты на Perl имеют свои нежные привязанности к тому или иному виду ограничителей.

Поиск в строках — не единственное применение для регулярных выражений. Часто требуется изменить строку, соответствующую шаблону, исключив некоторые части или добавив что-то новое. Для таких нужд применяется оператор замены s/⋯/⋯/. Мы видим, что оператор замены состоит из двух частей. Первая часть — это шаблон поиска, такой же, как и в операторе поиска m/…/. Вторая часть указывает, на что следует заменить найденное. Важно отметить, что оператор замены, вообще говоря, меняет содержимое строки — недаром он так называется. Изменения происходят только если строка соответствует шаблону в первой части оператора.

Может сложиться впечатление, что с помощью регулярных выражений в Perl можно осуществлять поиск лишь в переменной $_. На самом деле поиск возможен в любой скалярной переменной, в ячейке массива (обычного и ассоциативного), и вообще в произвольном скалярном значении. Нужно лишь связать переменную или значение с оператором поиска. Для этого имеется специальный оператор =~ — оператор связывания. В отсутствие оператора связывания поиск считается связанным с переменной по умолчанию.

То же самое относится и к оператору замены с тем лишь исключением, что он может быть связан только с переменной, поскольку оператор замены меняет связанную с ним величину. Будет ошибкой связать замену с константой:

'константа'=~s/к/К/;

Оператор связывания возвращает истинное или ложное значение в зависимости от успешности поиска. У него в компании имеется дополнительный оператор !~, который, наоборот, возвращает ложное значение в случае успешного поиска, и истинное в случае неуспешного. Таким образом, выражение $a!~m/⋯/ равносильно выражению !($a=~m/⋯/).

Встроенная процедура split использует шаблоны поиска. Она получает в качестве аргументов регулярное выражение и строку, а возвращает массив. В исходной строке отыскиваются все подстроки, соответствующие шаблону. Фрагменты строки, заключённые между найденными подстроками, как раз и возвращаются в массиве в порядке их появления. Если строка отсутствует в списке параметров split, используется, как обычно в таких случаях, переменная по умолчанию $_.

Например, строку, содержащую слово во всевозможных падежах, записанных через пробел, можно превратить в массив слов следующим образом:

my @cases=split /\ /, 'луна луну луне луну луной луне';

Если в качестве разделителей могут появиться другие пробельные символы, да ещё по нескольку подряд, шаблон следует заменить на \s+:

my @cases=split /\s+/, "луна
		луну
		луне
		луну
		луной
		луне";

Особый случай использования процедуры split возникает для пустого шаблона: в этом случае срока разбивается между символами, то есть split возвращает массив символов, составляющих строку. Следующий пример выводит все символы строки по одному в строке:

print "$_\n" for split //, 'Привет!';

Мы не упоминаем здесь многие другие возможности, предоставляемые процедурой split, отсылая читателя к документации на man-странице.

Информатика-54© А. Н. Швец