$pattern = q|HREF=["'](\S+?)["']>([^<]+?)</A>|; # шаблон
$htm =~ m/$pattern/; # поиск соответствия в $htm
# в $1 = 'http://regexp.ru/'
# в $2 = 'Регулярные выражения'
Сохраненные совпадения доступны и во время обработки регулярного выражения, но через переменные с именами \1, \2 и так далее. Эти переменные называются обратными ссылками (backreference) на найденные соответствия. Так, например, можно найти два одинаковых слова, стоящих в тексте друг за другом через пробелы (возможно, по ошибке):
my $string = "Уже скоро скоро наступит весна!";
my $pattern = '(\S+)\s+\1';
# (\S+) сохранит значение 'скоро' в \1
$string =~ m/$pattern/; # соответствие: 'скоро скоро'
Операция сопоставления, употребленная в списочном контексте, возвращает список найденных соответствий, для которых было предусмотрено сохранение значений. Поэтому удобно сохранять найденные значения в массиве или в списке скалярных переменных. Например, извлечем из текстовой строки последовательность цифр, похожую на время:
my $text = 'Начало в 12:25:00.'; # строка с данными
my $pattern = '(\d\d):(\d\d):(\d\d)'; # образец для поиска
my @time = $text =~ m/$pattern/; # сохраним в массиве
my ($hh, $mm, $ss) = $text =~ m/$pattern/; # и в списке
Можно находить любое количество соответствий образцу в одной операции сопоставления. Это делается с помощью модификатора глобального поиска.
До сих пор операция сопоставления прекращала работу и возвращала результат, когда находилось первое соответствие строки указанному шаблону. Если для операции сопоставления указать модификатор /g (global), то она будет искать в строке все соответствия образцу, организуя неявный цикл обработки регулярного выражения. Например, так можно найти все числа в строке с помощью одного шаблона:
my @numbers = 'Не 12.5, а 25!' =~ /(\d+)/g; # глобальный поиск
# в @numbers будет (12, 5, 25)
Ранее в этой лекции уже упоминался модификатор /i, устанавливающий поиск с игнорированием разницы между заглавными и строчными буквами. Перечислим модификаторы для операции сопоставления:
[x]. /g - искать в тексте все соответствия образцу (Global);
[x]. /i - искать соответствие образцу без учета регистра букв (case-Insensitive);
[x]. /s - рассматривать текст как одну строку (Single-line);
[x]. /m - рассматривать текст как многострочный (Multi-line) с учетом \n ;
[x]. /o - один раз откомпилировать регулярное выражение (Once);
[x]. /x - использовать расширенный синтаксис регулярных выражений (eXtended).
Из всех модификаторов, пожалуй, самый интересный - последний, который позволяет записывать регулярные выражения в структурированном и понятном для человека виде и даже сопровождать комментариями! Так, например, можно более понятно и красиво переписать регулярное выражение, приведенное в начале лекции:
m/ # начало регулярного выражения
<A # начало тега: <A
[^>]+? # далее могут быть любые символы, кроме >
HREF # определение гиперссылки
\s*=\s* # знак =, возможно окруженный пробелами
["']? # может быть открывающая кавычка или апостроф
( # начало захвата значения
[^'" >]+? # адрес ссылки: все, кроме ',",пробела и >
) # конец захвата значения
['"]? # может быть закрывающая кавычка или апостроф
\s* # за которым могут быть пробелы
> # конец тега
/igx; # конец регулярного выражения
# соответствует, например: <a id='ru' href="index.html">
Записанное в таком виде, регулярное выражение становится доступным для понимания, анализа и модификации. А поскольку регулярные выражения компилируются, то пробельные символы и комментарии не влияют на быстродействие программы.
Кроме поиска, регулярные выражения часто применяются для замены найденных совпадений на новые значения. Для этого существует операция замены (substitution), которая пытается найти в строковой переменной соответствие образцу, а если находит, то заменяет найденную подстроку на указанное значение. Операция замены выглядит так:
$variable =~ s/образец/замена/;
# в переменной $variable отыскивается строка 'образец',
# и если найдена, то она заменяется на 'замена'
Все, что говорилось до этого про операцию сопоставления, применимо для левой части операции замены, в которой указывается образец поиска. Левая и правая части операции замены интерполируются, поэтому там могут использоваться escape-последовательности и переменные.