До сих пор здесь обсуждался язык регулярных выражений вне всякой связи с каким-либо языком программирования. Пришло время обсудить, как пользоваться возможностями регулярных выражений в программах на Perl.
Для поиска по шаблону в языке Perl предусмотрен оператор
поиска
m/⋯/. Вместо многоточия следует поместить шаблон. Текст,
в котором производится поиск, должен находиться в переменной по умолчанию
$_
. Тогда оператор m/⋯/ возвращает логическое
значение, истинное при успешном поиске, и ложное в противном случае. Если
шаблон содержит группы захвата, то в качестве побочного эффекта при успешном
поиске получат свои значения групповые переменные $1
,
$2
, … — те самые буферы захвата, о которых шла речь
в разделе «Захват».
Следующий фрагмент кода проверяет, содержит ли переменная $_
десятичную запись целого числа (как минимум одна десятичная цифра, которой,
возможно, предшествует знак минуса):
Perlif(m/^\-?\d+$/) { print "число\n"; } else { print "не число\n"; }
или
Perlprint(m/^\-?\d+$/? '': 'не ', "число\n");
Мы видим, что знаки косой (слэши) черты служат ограничителями, внутри которых
заключён шаблон. Это, конечно, означает, что просто так эти знаки не получится
использовать в шаблоне. Не нужно быть очень умным, чтобы сообразить, как обойти
эту трудность. Разумеется, следует ставить бэкслэши перед слэшами. К примеру,
если в переменной $_
находится полное имя файла, проверка
того, лежит ли файл в директории /usr/bin
, будет выглядеть так:
Perlif(m/^\/usr\/bin\//) { print "лежит"; } else { print "не лежит"; }
Если часто приходится обрабатывать имена файлов и директорий с помощью
регулярных выражений, удобно использовать альтернативные формы оператора поиска
с другими ограничителями: m#⋯#, m!⋯!,
m+⋯+, m(⋯), m[⋯]. Сравните: m/^\/usr\/bin\//
и m#^/usr/bin/#
. Тогда, помещая в шаблон выбранный символ
ограничителя (кроме скобок), нужно позаботиться о его защите и вставить перед
ним бэкслэш. Со скобками в качестве ограничителей такой проблемы нет (почему?).
Программисты на Perl имеют свои нежные привязанности к тому или иному виду
ограничителей.
Поиск в строках — не единственное применение для регулярных выражений. Часто требуется изменить строку, соответствующую шаблону, исключив некоторые части или добавив что-то новое. Для таких нужд применяется оператор замены s/⋯/⋯/. Мы видим, что оператор замены состоит из двух частей. Первая часть — это шаблон поиска, такой же, как и в операторе поиска m/…/. Вторая часть указывает, на что следует заменить найденное. Важно отметить, что оператор замены, вообще говоря, меняет содержимое строки — недаром он так называется. Изменения происходят только если строка соответствует шаблону в первой части оператора.
Требуется заменить в переменной $_
несколько идущих подряд
пробелов на один. Эта задача решается при помощи оператора s/\ +/ /
.
В переменной $_
содержатся фамилия, имя и отчество человека,
разделённые пробелами, например, Чайковский Пётр Ильич
.
Нужно заменить имя и отчество инициалами: Чайковский П. И.
.
Решение: s/^(\S+) (\S)\S* (\S)\S*$/$1 $2. $3./
(здесь предполагается, что фамилия, имя и отчество не содержат пробелов, что,
как правило, верно, но не всегда).
Этот пример показывает, что переменные захвата вполне можно использовать во второй части оператора замены.
Если подобным образом нужно обработать все элементы массива, применим цикл:
Perls/^(\S+) (\S)\S* (\S)\S*$/$1 $2. $3./ for @persons;
Может сложиться впечатление, что с помощью регулярных выражений в Perl можно
осуществлять поиск лишь в переменной $_
. На самом деле поиск
возможен в любой скалярной переменной, в ячейке массива (обычного
и ассоциативного), и вообще в произвольном скалярном значении. Нужно лишь
связать переменную или значение с оператором поиска. Для этого имеется
специальный оператор =~ — оператор
связывания.
В отсутствие оператора связывания поиск считается связанным с переменной по
умолчанию.
То же самое относится и к оператору замены с тем лишь исключением, что он может быть связан только с переменной, поскольку оператор замены меняет связанную с ним величину. Будет ошибкой связать замену с константой:
Perl'константа'=~s/к/К/;
Оператор связывания возвращает истинное или ложное значение в зависимости от
успешности поиска. У него в компании имеется дополнительный оператор
!~, который, наоборот, возвращает ложное значение в случае
успешного поиска, и истинное в случае неуспешного. Таким образом, выражение
$a!~m/⋯/
равносильно выражению !($a=~m/⋯/)
.
Встроенная процедура split
использует шаблоны поиска. Она
получает в качестве аргументов регулярное выражение и строку, а возвращает
массив. В исходной строке отыскиваются все подстроки, соответствующие шаблону.
Фрагменты строки, заключённые между найденными подстроками, как раз
и возвращаются в массиве в порядке их появления. Если строка отсутствует
в списке параметров split
, используется, как обычно
в таких случаях, переменная по умолчанию $_
.
Например, строку, содержащую слово во всевозможных падежах, записанных через пробел, можно превратить в массив слов следующим образом:
Perlmy @cases=split /\ /, 'луна луну луне луну луной луне';
Если в качестве разделителей могут появиться другие пробельные символы, да ещё
по нескольку подряд, шаблон следует заменить на \s+
:
Perlmy @cases=split /\s+/, "луна луну луне луну луной луне";
Особый случай использования процедуры split
возникает для
пустого шаблона: в этом случае срока разбивается между символами, то есть
split
возвращает массив символов, составляющих строку.
Следующий пример выводит все символы строки по одному в строке:
Perlprint "$_\n" for split //, 'Привет!';
П
р
и
в
е
т
!
Мы не упоминаем здесь многие другие возможности, предоставляемые процедурой
split
, отсылая читателя к документации на
man-странице.