Опубликован: 18.06.2007 | Доступ: свободный | Студентов: 1391 / 36 | Оценка: 4.14 / 3.29 | Длительность: 12:44:00
ISBN: 978-5-94774-604-4
Лекция 3:

Дополнительные конструкции в регулярных выражениях

< Лекция 2 || Лекция 3: 12345 || Лекция 4 >

3.3. Опережающая проверка

Это сложное условие ( мнимый символ, якорь ). Эту проверку еще называют "заглядыванием вперед". Вводится она конструкцией

(?= шаблон )

Шаблон может быть как угодно сложным. Это условие истинно, если в текущей позиции находится текст, совпадающий с заданным шаблоном. Обратите внимание, что эти условные конструкции совпадают не с текстом, а с позицией в тексте подобно своим более простым собратьям \b, \A, $ и т.д.

Замечу, что атомарная группировка имитируется позитивной опережающей проверкой и обратной ссылкой:

(?> шаблон )  эквивалентно  (?=( шаблон ))\1

Происходит это потому, что после выполнения опережающей (как и ретроспективной) проверки уничтожаются все сохраненные состояния, возникшие внутри нее.

Имеется противоположный случай проверки - негативная опережающая проверка:

(?! шаблон )

Такое условие истинно, если в текущей позиции нет текста, совпадающего с заданным шаблоном.

Например, шаблон

\w+(?=\s+)

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

Рассмотрим такой пример:

$_='abc';
print "1\n" if /a(?=(b))bc/;
print $1;

Будут напечатаны такие строки:

1
b

Как видим, после совпадения с символом a после него ищется символ b. Он находится, и поиск продолжается дальше. Если сразу бы после a не стоял символ b, то поиск потерпел бы неудачу и началась бы следующая итерация, т.к. сохраненных состояний, к которым можно вернуться, нет. Внутри опережающей проверки этот символ захватывается в переменную $1, после чего проверка заканчивается успешно, и текущая позиция в строке возвращается к символу b. Затем выполняется соответствие подшаблона bc символам bc, на этом оператор поиска успешно завершается.

Подобные сложные проверки бывают необходимы в сложных случаях, когда надо принять решение в зависимости от того, какой фрагмент текста находится в текущей позиции (или вообще впереди нее). Эти условия обычно используются в условных конструкциях, о которых речь впереди.

Обратите внимание на интересную особенность сложных условий: в результате работы оператора

"a" =~ /(?=(a))/

переменная $1 получит значение a, а в результате работы похожего регулярного выражения

"a" =~ /((?=a))/

переменная $1 получит пустое значение. Это можно объяснить тем, что в первом случае внутри сложного условия происходит захват буквы a, а затем после выхода за это сложное условие (на конец регулярного выражения ) текущая позиция в шаблоне возвращается в точку перед буквой a, но сама буква уже сидит в переменной $1. Во втором случае после выполнения фрагмента шаблона ((?=a текущая позиция в шаблоне передвигается за букву a, но после закрытия скобки в сложном условии ((?=a) происходит возврат текущей позиции в шаблоне перед буквой а, и после закрытия захватывающей скобки эта текущая позиция остается перед буквой a, как и в момент открытия захватывающей пары скобок. В результата эта пара скобок захватывает пустой фрагмент текста.

< Лекция 2 || Лекция 3: 12345 || Лекция 4 >
Константин Бражников
Константин Бражников
Россия
Mike .
Mike .
Россия