Группировка в шаблонах

Как и в математических операциях, круглые скобки () используются для группировки элементов выражения. Таким образом, круглые скобки также являются метасимволами. Например, шаблон /fred+/ совпадает с такими строками, как fredddddd, но подобные строки редко встречаются на практике. С другой стороны, шаблон /(fred)+/ совпадает в строках вида fredfredfred, а это уже больше похоже на то, что вам может понадобиться. А как насчет шаблона /(fred)*/? Как ни странно, он совпадет даже в такой строке, как hello, world. Круглые скобки также дают возможность повторно использовать часть строки, непосредственно предшествующую совпадению. Мы можем применять обратные ссылки для обращения к тексту, совпавшему с элементами выражения в круглых скобках. Обратная ссылка обозначается обратной косой чертой, за которой следует цифра: \1, \2 и т. д. Цифра обозначает номер пары скобок.

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

$_ = "abba";
if (/(.)\1/) { # Совпадает с 'bb'
print "It matched same character next to itself!\n";
}

Запись (.)\1 говорит, что выражение совпадает с символом, стоящим справа от самого себя.


Сначала (.) совпадает с a, но при переходе к обратной ссылке, согласно которой дальше должен совпасть символ a, следующая проверка завершается неудачей. Perl начинает проверку заново, проверяя (.) на совпадение со следующим символом b. Теперь обратная ссылка \1 говорит, что в следующей позиции шаблона стоит символ b, который успешно совпадает. Обратная ссылка не обязана находиться сразу же за группой в круглых скобках. Следующий шаблон совпадает с любыми четырьмя символами, отличными от символа новой строки, после литерала y; далее обратная ссылка \1 показывает, что те же четыре символа должны находиться после d:

$_ = "yabba dabba doo";
if (/y(....) d\1/) {
print "It matched the same after y and d!\n";
}

Выражение может содержать несколько групп круглых скобок, при этом каждой группе соответствует собственная обратная ссылка. В следующем примере первая пара скобок совпадает с любым символом, кроме символа новой строки, за которым следует вторая пара скобок, также совпадающая с любым символом, кроме символа новой строки. После этих двух групп следует обратная ссылка \2, за которой следует обратная ссылка \1. Фактически в строке ищутся палиндромы (например, abba):

$_ = "yabba dabba doo";
if (/y(.)(.)\2\1/) { # Совпадает с 'abba'
print "It matched the same after y and d!\n";
}

Возникает резонный вопрос: «Как определить, какой номер соответствует той или иной группе?» К счастью, Ларри выбрал способ, наиболее понятный для нас, людей: просто посчитайте открывающие круглые скобки, не обращая внимание на вложение:

$_ = "yabba dabba doo";
if (/y((.)(.)\3\2) d\1/) {
print "It matched!\n";
}

Регулярное выражение даже можно записать так, чтобы в нем были четко видны разные части (хотя следующий фрагмент не является действительным регулярным выражением1):

( # Первая открывающая скобка
(.) # Вторая открывающая скобка
(.) # Третья открывающая скобка
\3
\2
)

В Perl 5.10 появился новый способ обозначения обратных ссылок.


Комбинация из обратной косой черты и номера заменяется конструкцией \g{N}, где N – номер обратной ссылки. Такая конструкция позволяет более четко выразить предполагаемую цель шаблона. Представьте, что будет, если обратная ссылка должна использоваться рядом с числовой частью шаблона. В регулярном выражении запись \1 обозначает повторение символа, совпавшего с предыдущей парой круглых скобок, а за ней следует литеральная строка 11:

$_ = "aa11bb";
if (/(.)\111/) {
print "It matched!\n";
}

Perl приходится гадать, что имелось в виду: \1, \11 или \111? Perl может создать столько обратных ссылок, сколько потребуется, поэтому он считает, что мы имели в виду \111. А поскольку выражение не содержит 111 (и даже 11) пар круглых скобок, Perl сообщает об этом при попытке откомпилировать программу. Конструкция \g{1} позволяет однозначно отделить обратную ссылку от литеральной части шаблона:

use 5.010;
$_ = "aa11bb";
if (/(.)\g{1}11/) {
print "It matched!\n";
}

Запись \g{N} также позволяет использовать отрицательные числа. Вместо абсолютного номера группы в круглых скобках можно указать относительную обратную ссылку.


Перепишем последний пример так, чтобы та же задача решалась с использованием номера –1:

use 5.010;
$_ = "aa11bb";
if (/(.)\g{-1}11/) {
print "It matched!\n";
}

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

use 5.010;
$_ = "aa11bb";
if (/(.)(.)\g{-1}11/) {
print "It matched!\n";.



Оцените статью: (0 голосов)
0 5 0

Статьи из раздела Perl на эту тему:
Альтернатива
Инвертированные сокращения
О метасимволах
Простые квантификаторы
Простые регулярные выражения

Вернуться в раздел: Perl / 6. В мире регулярных выражений