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

Динамические регулярные выражения

< Лекция 11 || Лекция 12: 12345 || Лекция 13 >

12.2. Поиск вложенных конструкций

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

Рассмотрим задачу удаления всех комментариев, которые заключены в фигурные скобки, вместе с этими скобками. При этом предположим, что эти комментарии могут иметь произвольную вложенность. Т.е. надо уничтожить все правильно сбалансированные серии фигурных скобок вместе с их содержимым. От строки

$_=" {a{b{c{{d{}m}e}f}}gf{ }f";

после этого должно остаться ' {agff'.

Будем рассуждать от легкого случая к более сложным. Если бы речь шла только о первом уровне вложенности: …{…}…, то мы могли бы создать такой объект регулярного выражения:

my $level0=qr/(?>[^{}]*)/;

который соответствует всему кроме фгурных скобок. А оператор замены был бы таким:

s/\{$level0}//g;

Напоминаю, что символ } не обязательно маскировать, т.к. он в отличие от символа { не является метасимволом регулярного выражения.

Эта программа корректно бы удаляла комментарии первого уровня вложенности. От строки a{b}c осталось бы ac. Но если бы мы задали этой программе строку

a{b{c}d}e

то в результате получили бы остаток

a{bd}e

Удаляются только скобки с фрагментами, которые не содержат этих скобок. Мы могли бы повторять подстановку, пока оператор s/…/…/ возвращает ненулевой результат, но нам нужен общий метод для любого уровня вложенности. С этой целью расширим наш объект регулярного выражения. Он должен совпадать не только с текстом без скобок, но и с текстом без скобок, который ограничен этими фигурными скобками. Это мы сделаем с помощью конструкции альтернативного шаблона:

my $level1=qr/(?>[^{}]|\{$level0})*/;

Здесь мы воспользовались тем, что у нас уже есть регулярное выражение, которое соответствует фрагменту текста без фигурных скобок, это объект $level0. Чтобы фрагменты текста без скобок поглощались быстрее, можно поставить квантификатор +:

my $level1=qr/(?>[^{}]+|\{$level0})*/;

А чтобы не создавалось ненужных сохраненных состояний, можно это еще взять в атомарные скобки:

my $level1=qr/(?>(?>[^{}]+)|\{$level0})*/;

Программа

$_='a{b{c}d}e';
my $level0=qr/(?>[^{}]*)/;
my $level1=qr/(?>(?>[^{}]+)|\{$level0})*/;
s/\{$level1}//g;
print $_;

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

ae

Но если ей дать текст со скобками третьего уровня вложенности, то она оставляет скобки первого уровня вложенности:

$_='a{b{c{d}}e}f';
my $level0=qr/(?>[^{}]*)/;
my $level1=qr/(?>(?>[^{}]+)|\{$level0})*/;
s/\{$level1}//g;
print $_;

Выводится

a{be}f

Мы могли бы по аналогии создать объект $level3 и т.д., но динамические регулярные выражения позволяют сразу создать объект $levelN для произвольного уровня вложенности:

#!/usr/bin/perl -w
use strict;

$_=" {a{b{c{{d{}m}e}f}}gf{ }f";
my $levelN;
$levelN=qr
/(?>
    (?>[^{}]+)|		   # все кроме фигурных скобок
         \{(??{$levelN})}  # или текст, соответств. всему шаблону, ограниченный скобками
  )*			   # сколько угодно раз
/x;
s/\{$levelN}//g;
print $_;

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

{agff

Это верный результат.

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