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


         

которое появится, когда динамическое регулярное


которое появится, когда динамическое регулярное выражение вернет подшаблон (?!).

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

Здесь опять замечу, что это регулярное это выражение возвращает несовпадение и используется только ради побочного эффекта (установки переменной $res).

Насколько эффективно работает это регулярное выражение? Вставьте встроенный код

Perl после атомарных скобок, который будет печатать содержимое переменной $1:

/((\d) (?{$d=$+}) (?> (??{ ++$d < 10 ? "$d" : "(?!)" })* ) ) (?{print "$1\n"}) (?{ # Эти символы нельзя разделять if (length $1 > $len) { $len=length $1; $res=$1; } }) # Эту скобку нельзя отделять от предыдущей скобки "}" (?!) /x; print $res if defined $res;

В результате на печати получим:

0123 123 23 3 1234 234 34 4 3456789 456789 56789 6789 789 89 9 1 0 3456789

Видим, что вначале регулярное выражение находит длиннейшую последовательность цифр, а потом перестартовывает с каждой следующей цифры этой последовательности благодаря второму подшаблону (?!). Хотелось бы, чтобы вместо этого начальная позиция при итерациях устанавливалась сразу за найденной последовательностью цифр, дабы не делать лишней работы. Но мне кажется, это невозможно, т.к. присвоение внутри регулярного выражения функции pos (pos($_)=…) не дает эффекта.

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

(?(?{$len == 4})\G(?!))

При достижении этого условия встроенный код Perl вернет истину, и на место всей условной конструкции будет подставлен подшаблон

\G(?!)

Он говорит, что с конца предыдущего совпадения (или с начала текста при первой итерации поиска) нет совпадения. На этом все регулярное выражение закончит работу, т.к. итерация его со следующей позиции невозможна из-за привязки к концу предыдущего совпадения. В том месте, где вы установили, что надо поскорее выйти из регулярного выражения, подставьте подшаблон (?!), чтобы произошла итерация всего регулярного выражения. Но помните, что она не произойдет до тех пор, пока слева от текущей позици в шаблоне имеются квантификаторы или конструкции выбора альтернативы с сохраненными состояниями.

Что будет, если убрать атомарную группировку?

/((\d) (?{$d=$+})

(??{ ++$d < 10 ? "$d" : "(?!)" })*

) (?{print "$1\n"}) (?{ # Эти символы нельзя разделять if (length $1 > $len) { $len=length $1; $res=$1; } }) # Эту скобку нельзя отделять от предыдущей скобки "}" (?!) /x; print $res if defined $res;

Тогда на печать выйдет гораздо больше строк:

0123 012 01 0 123 12 1 23 2 3 1234 123 12 1 234 23 2 34 3 4 3456789 345678 34567 3456 345 34 3 456789 45678 4567 456 45 4 56789 5678 567 56 5 6789 678 67 6 789 78 7 89 8 9 1 0 3456789

Из этой распечатки видно, что после выполнения второго подшаблона (?!) не происходит итерация всего регулярного выражения, как в первом случае, ведь квантификатор * имеет сохраненные состояния. Он начинает отдавать по одной захваченной цифре, пока не отдаст их все. Только после этого происходит рестарт всего регулярного выражения со следующего символа целевого текста.


Содержание  Назад  Вперед





Forekc.ru
Рефераты, дипломы, курсовые, выпускные и квалификационные работы, диссертации, учебники, учебные пособия, лекции, методические пособия и рекомендации, программы и курсы обучения, публикации из профильных изданий