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


Атомарная группировка


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

\s*=\s*

Представим, что вокруг знака равенства стояли бы пробелы и впоследствии ссылка не была бы найдена. Тогда произошел бы возврат и квантификатор \s* отдал бы один пробел для продолжения поиска. Но мы-то знаем, что это не повлияет на нахождение ссылки, так зачем проделывать ненужную работу? Для уничтожения сохраненных состояний подшаблон \s* надо заключить в специальную скобочную конструкцию:

(?>\s*)

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

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

<a(?>\s+) (?>[^>]*) и т.д.

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

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

(?>\w*)c

и строку

abc

Как вы уже догадались, совпадения не будет найдено. Квантификатор * захватит все три символа, а после выхода за скобки сохраненные состояния будут уничтожены, поэтому этот квантификатор ни за что не отдаст захваченное. Будут перепробованы итерации со второго, третьего символа и с конца строки, но все будет безрезультатно. Без атомарной группировки совпадение было бы найдено при первой итерации с начала строки.

А что будет в случае минимального квантификатора? Возьмем шаблон

(?>\w*?)c




Начало  Назад  Вперед