Регулярные выражения Perl и их применение

     Здесь фильтр помехоподавляющий ФП-6. |   

Ретроспективная проверка


Имеется аналогичная возможность также "заглянуть назад":

(?<= шаблон )

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

$_='abcd'; print "1\n" if /ab(?<=(ab))/; print $1;

В результате получим вывод

1 ab

Как видим, захват текста в этих якорях также происходит.

Негативная ретроспективная проверка задается выражением

(?<! шаблон )

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

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

Иначе пришлось бы искать с начала всего текста, а это большие непроизводительные затраты времени. Поэтому шаблон не может содержать квантификаторы переменной длины, а все альтернативы в альтернативных конструкциях должны совпадать с текстом одной и той же длины. Вот примеры ошибок:

(?<=\w+) (?<=\w{1,2}) (?<=\w{3}|abcd)

В первых двух случаях имеем переменную длину квантификатора, а в последнем - разную длину альтернатив.

В качестве примера использования этих якорей рассмотрим задачу разделения разрядов числа запятыми. Большие числа удобнее воспринимать, когда они поделены запятыми по три разряда: 12,345,678. Хотя тройки разрядов отсчитываются справа, а механизм поиска просматривает текст слева, эту техническую сложность нетрудно обойти. Сформулируем условие вставки запятой так: запятая вставляется в позицию, слева от которой имеется цифра, а справа - произвольное ненулевое число групп из трех цифр и далее не стоит цифра. Вот программа, которая моделирует этот пример:

$_='number 1: 12345678 number 2: 98765432154321'; s/(?<=\d)(?=(?:\d{3})+(?!\d))/,/g; print $_;

На печать выведется

number 1: 12,345,678 number 2: 98,765,432,154,321


Вторая проверка здесь сложная: она включает в себя еще одну проверку того, что дальше не стоит цифра. Модификатор g обеспечивает расстановку запятых по всему тексту в нужных местах.

Если бы мы вынесли за скобку проверку (?!\d) и написали бы так:

s/(?<=\d)(?=(?:\d{3})+)(?!\d)/,/g;

то это было бы неправильно. Смысл получился бы таким: позиция, перед которой стоит цифра, за которой идет группа из троек цифр и за которой нет цифры. Этот набор условий никогда не выполняется.

Благодаря тому, что позиционные проверки не поглощают текст, для данной позиции текста можно записать сколько угодно таких проверок. Все они должны выполняться, иначе произойдет локальная неудача поиска. Например:

/(?=\d)(?![09])/;

означает, что в этой позиции должна стоять цифра и она не должна быть равна нулю и девяти. Это равносильно условию

/(?=[1-8])/;

Ко всему сказанному добавлю, что к позиционным проверкам, как и вообще к условиям с нулевой длиной совпадения, нельзя ставить квантификаторы.


Содержание раздела