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


         

Встроенный код и поиск вложенных конструкций


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

2*(3+2*(5-1)-2)+12

содержит конструкцию из правильно закрытых скобок, а строки

( ) ) ( )

и

( ( ) ( )

содержат неправильно сбалансированные круглые скобки.

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

Схема регулярного выражения будет такая:

^ # поиск от начала текста (?> # поиск без возвратов (?: (?> [^()]+ ) # все кроме круглых скобок без возврата | \( # или открывающая круглая скобка | \) # или закрывающая круглая скобка )* # сколько угодно раз ) $ # поиск до конца текста

Вначале счетчик $ctop (count of open parens) содержит 0. При встрече открывающей скобки выполняем код

(?{ ++$ctop })

При встрече закрывающей скобки выполняем условный оператор с кодом Perl в условии:

(?(?{ $ctop }) (?{ --$ctop }) | (?!) )

А если к этому моменту $ctop равен нулю, то подставляем шаблон (?!), который приведет к несовпадению для всего регулярного выражения.

В конец регулярного выражения подставим код

(?(?{ $ctop }) (?!) )

который тоже приведет к несовпадению для всего шаблона, если счетчик $ctop не будет равен нулю.

Теперь вся программа:

$_='( () ) ( ) (()())'; my $ctop=0; if (/ ^ (?> (?: (?> [^()]+ ) | \( (?{ ++$ctop }) | \) (?(?{ $ctop }) (?{ --$ctop }) | (?!) ) )* ) (?(?{ $ctop }) (?!) ) $ /x ) { print 'Match' } else { print 'Not match' }




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