PHP: Синтаксис регулярных выражений - Manual

downloads | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

preg_grep Модификаторы шаблонов

Last updated: Fri, 26 Jan 2007

view this page in

# Синтаксис регулярных выражений

Синтаксис регулярных выражений -- Описание синтаксиса Perl-совместимых регулярных выражений (PCRE)

## Вступление

Библиотека PCRE является набором функций, которые реализуют поиск по шаблону, используя синтаксис, подобный синтаксису Perl 5 с небольшими отличиями. Текущая реализация соответствует версии Perl 5.005.

## Отличия от Perl

Разница описана относительно версии Perl 5.005.

1. По умолчанию пробельными символами являются все символы, распознаваемые библиотечной функцией языка Си isspace(). Это позволяет собрать PCRE библиотеку с произвольными символьными наборами. В стандартной поставке функция isspace() определяет как пробельные следующие символы: пробел, разрыв страницы, начло строки, перевод каретки, горизонтальную и вертикальную табуляцию. Начиная с версии Perl 5.002, символ вертикальной табуляции \v не является пробельным и, соответственно, не соответствует классу символов \s.

2. PCRE не позволяет использовать квантификаторы повторения в условных выражениях. Perl позволяет это делать, но получаемый результат может существенно отличаться от ожидаемого. Например, (?!a){3} не означает, что три следующих символа будут не 'a'. Он всего лишь трижды утверждает, что следующий символ не 'a'.

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

4. Несмотря на то, что символ, соответствующий ASCII-коду 0 (бинарный ноль), допускается в обрабатываемом тексте, он недопустим в шаблоне (так как передается в качестве аргумента Си-функции как нормальная строка, завершаемая нулевым символом). Cледующая служебная последовательность "\\x00" может быть использована для представления бинарного ноля.

5. Следующие служебные последовательности, используемые в Perl, не поддерживаются: \l, \u, \L, \U, \E, \Q. Это связано с тем, что обработка указанных последовательностей производится внутренним Perl-механизмом обработки строк и не является частью механизма регулярных выражений.

6. Perl модификатор \G не поддерживается, так как он не входит в рамки простого сопоставления шаблону.

7. Достаточно очевидно, что PCRE не поддерживает конструкции вида (?{code}).

8. Теперь немного о чудаковатости в Perl 5.005_02, связанной с фиксацией результата в случае, когда часть шаблона повторяется. Например, применяя шаблон /^(a(b)?)+$/ к строке "aba", переменная $2 соответствует 'b'. Но при применении шаблона /^(aa(bb)?)+$/ к строке "aabbaa" переменная $2 оказывается неустановленной. А в случае, если шаблон изменить на /^(aa(b(b))?)+$/, переменные $2 и $3 окажутся установленными. В Perl 5.004, в обоих случаях переменная $2 будет содержать соответствующее значение, что соответствует PCRE. Если в будущем Perl изменит поведение в данной ситуации, PCRE также может измениться.

9. Еще одна несовместимость, не находящая разумного объяснения. Шаблон /^(a)?(?(1)a|b)+$/ соответствует строке 'a' в PERL, но не в PCRE. В то же время шаблон /^(a)?a/ соответствует строке 'a' и в Perl и в PCRE, оставляя переменную $1 неустановленной.

10. PCRE также предоставляет некоторое расширение возможностей Perl для обработки регулярных выражений:

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

    2. В случае, если модификатор PCRE_DOLLAR_ENDONLY используется и PCRE_MULTILINE не используется, специальный символ '$' соответствует исключительно концу обрабатываемых данных.

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

    4. Модификатор PCRE_UNGREEDY инвертирует жадность квантификаторов, таким образом они по умолчанию не жадные. Но становятся жадными, если за ними следует символ '?'.

## Регулярные выражения в деталях

### Предисловие

Ниже описан синтаксис Perl-совместимых регулярных выражений (PCRE). Регулярные выражения также хорошо описаны в документации языка Perl и в достаточно большом количестве книг, с изобилием примеров, например, книга "Mastering Regular Expressions", написанная Effrey Friedl's (ISBN 1-56592-257-3).

Регулярное выражение - это шаблон, применяемый к заданному тексту слева направо. Большая часть символов сохраняет свое значение в шаблоне и означает совпадение с соответствующим символом. Банальный пример: шаблон `The quick brown fox` соответствует той части строки, которая идентична приведенной фразе.

### Метасимволы

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

Существуют два различных набора метасимволов: те, которые используются внутри квадратных скобок, и те, которые используются вне квадратных скобок. Рассмотрим их более детально. Вне квадратных скобок используются следующие метасимволы:

\

  общий экранирующий символ, допускающий несколько вариантов применения

^

  декларирует начало данных (или линии, в многострочном режиме)

$

  декларирует конец данных (или линии, в многострочном режиме)

.

  соответствует любому символу, кроме перевода строки (по умолчанию)

[

  начало описания символьного класса

]

  конец описания символьного класса

|

  начало ветки условного выбора

(

  Начало подмаски

)

  конец подмаски

?

  расширяет смысл метасимвола '(' , квантификатор, означающий ноль либо одно вхождение, квантификатор жадности

*

  квантификатор, означающий ноль или более вхождений

+

  квантификатор, означающий одно или более вхождений

{

  начало количественного квантификатора

}

  конец количественного квантификатора

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

\

  общий экранирующий символ

^

  означает отрицание класса, допустим только в начале класса

-

  означает символьный интервал

]

  завершает символьный класс

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

### Обратный слеш

Символ '\' имеет несколько применений. Прежде всего, если он предшествует не буквенно-цифровому символу, он снимает с него специальное значение. Применение обратного слеша как экранирующего символа допустимо как в символьном классе, так и вне него.

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

В случае, если указан модификатор PCRE_EXTENDED, пробельные символы в шаблоне (вне описания символьного класса) игнорируются. Также игнорируется часть строки, находящаяся между символом '#' (опять же, не участвующем в описании символьного класса) и следующим символом перевода строки. В таком случае обратный слеш можно применять как экранирующий символ для указания вхождений пробельным символов в шаблоне.

Второе примение обратного слеша заключается в том, что он позволяет использовать непечатные символы в описании шаблона. При том, что в PCRE нет ограничений на использование непечатных символов (исключая бинарный 0, который интерпретируется как конец шаблона), при редактировании программного кода в каком-либо текстовом редакторе гораздо удобнее использовать следующие комбинации:

\a

  символ оповещения, сигна, (шестнадцатиричный код 07)

\cx

  "Ctrl+x", где x - произвольный символ

\e

  escape (шестнадцатеричный код 1B)

\f

  разрыв страницы (шестнадцатиричный код 0C)

\n

  перевод строки (шестнадцатиричный код 0A)

\r

  возврат каретки (шестнадцатиричный код 0D)

\t

  табуляция (шестнадцатиричный код 09)

\xhh

  символ с шестнадцатиричным кодом hh

\ddd

  символ с восьмеричным кодом либо ссылка на подмаску

Если быть более точным, комбинация `\cx` интерпретируется следующим образом: если '`x`' - символ нижнего регистра, он преобразуется в верхний регистр. После этого шестой бит инвертируется. Таким образом '`\cz`' интерпретируется как 1A, в то время как '`\c;`' получает шестнадцатиричное значение 3B, а '`\c;`' - 7B.

После "`\x`" считываются еще две шестнадцатиричные цифры (они могут быть записаны в нижнем регистре).

После "`\0`" считываются две восьмеричные цифры. Если в записи менее двух цифр, будут использованы все фактически присутствующие цифры. Таким образом, последовательность "`\0\x\07`" будет интерпретирована как два бинарных нуля, за которыми следует символ оповещения (звонок). В случае, если вы используете представление числа в восьмеричном коде, убедитесь, что за начальным нулем следуют две значащие цифры.

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

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

\040

  еще один способ записи пробела

\40

  то же самое в случае, если данной записи предшествует менее сорока подмасок

\7

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

\11

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

\011

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

\0113

  символ табуляции, за которым следует цифра "3"

\113

  интерпретируется как символ с восьмеричным кодом 113 (так как ссылок на подмаски не может быть более чем 99)

\377

  байт, всецело состоящий из единичных битов

\81

  либо обратная ссылка, либо бинарный ноль, за которым следуют цифры "8" и "1"

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

Все последовательности, определяющие однобайтное значение, могут встречаться как внутри, так и вне символьных классов. Кроме того, внутри символьного класса запись "`\b`" интерпретируется как символ возврата ('backspace', шестнадцатеричный код 08). Вне символьного класса она имеет другое значение (какое именно, описано ниже).

Третье использование обратного слеша - указание общего типа символов:

\d

  любая десятичная цифра

\D

  любой символ, кроме десятичной цифры

\s

  любой пробельный символ

\S

  любой непробельный символ

\w

  Любой символ, образующий "слово"

\W

  Любой символ, не образующий "слово"

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

"word" символ - это произвольная цифра, буква или символ подчеркивания, проще говоря, любой символ, который может являться частью '`слова`' в Perl. Определение букв и цифр управляется символьными таблицами, с которыми PCRE был собран. И, как следствие, эти наборы могут отличаться в различных локализированных дистрибутивах. Например, в локали "fr" (Франция) некоторые символы с кодом выше 128 используются для записи ударных символов и, соответственно, соответствуют маске `\w`.

Описанные выше типы символов могут применяться как внутри, так и вне символьных классов, и соответствуют одному символу данного типа.

Четвертое использование обратного слеша - нотация некоторых формальных утверждений, описывающих условия касательно месторасположения особых позиций в строке и совершенно не затрагивающих сами символы. Такими управляющими последовательностями являются:

\b

  граница слова

\B

  не является границей слова

\A

  начало данных (независимо от многострочного режима)

\Z

  конец данных либо позиция перед последним символом строки, в случае если это символ перевода строки (независимо от многострочного режима)

\z

  конец данных (независимо от многострочного режима)

Описанные выше последовательности не могут встречаться в символьных классах (исключая комбинацию '`\b`', которая внутри класса означает символ возврата 'backspace').

Границей слова считается такая позиция в строке, в которой из текущего и последующего символа только один соответствует `\w` (т.е. один из них соответствует `\w`, а другой `\W`). Начало или конец строки также соответствуют границе слова в случае, если первый или, соответственно, последний символ совпадает с `\w`.

Специальные последовательности `\A`, `\Z` и `\z` отличаются от общеупотребляемых метасимволов начала строки '^' и конца строки '$' тем, что их поведение не зависит от наличия или отсутствия модификаторов. На них никак не влияют опции PCRE_MULTILINE и PCRE_DOLLAR_ENDONLY. Разница между `\Z` и `\Z` в том, что `\Z` соответствует позиции перед последним символом в случае, если последний символ - перевод строки. В то время, как `\z` соответствует исключительно концу данных.

### Метасимволы начала и конца строки

По умолчанию, вне символьного класса метасимвол начала строки '^' соответствует началу обрабатываемых данных (если не используются модификаторы). Внутри символьного класса он имеет совершенно другое значение.

Метасимвол '^' не обязан быть первым символом строки в случае, если в шаблоне используются несколько альтернатив, но должен быть первым символом в каждой из альтернатив, в которой он встречается, если шаблон когда-либо сопоставим с соответствующей веткой. Если все альтернативы начинаются с метасимвола начала строки, то шаблон ограничен для совпадения исключительно в начале строки, говорят что шаблон "заякорен". (Существуют и другие способы "заякорить" шаблон).

Соответствие метасимволу конца строки достигается только в конце строки или непосредственно перед последним символом в случае, если им является перевод строки (если модификаторы не указаны). Метасимвол конца строки не обязан быть последним символом шаблона в случае, если несколько альтернатив используется, но должен быть последним символом в каждой альтернативе, в которой он фигурирует. Внутри символьного класса символ '$' не имеет специального значения.

Поведение метасимвола конца строки может быть изменено при помощи модификатора PCRE_DOLLAR_ENDONLY так, чтобы он соответствовал исключительно концу строки. Данный флаг никак не касается специальной последовательности \Z.

Значение метасимволов начала и конца строки меняется в случае, если модификатор PCRE_MULTILINE используется. В таком случае, помимо совпадений в начале либо конце строки, метасимволы '^' и '$' соответствуют позиции непосредственно после символа перевода строки соответственно. Например, шаблон /^abc$/ встречается в строке def\nabc" в многострочном режиме и не встречается в нормальном режиме. Таким образом, шаблон который "заякорен" в однострочном режиме, не будет являться "заякоренным" в многострочном режиме. Модификатор PCRE_DOLLAR_ENDONLY игнорируется в случае, если модификатор PCRE_MULTILINE установлен.

Следует заметить, что служебные последовательности \A, \Z и \z могут использоваться для сопоставления с началом либо концом строки в обоих режимах. И если все ветви шаблона начинаются с \A, шаблон будет заякорен независимо от присутствия модификатора PCRE_MULTILINE.

### Метасимвол точка

Вне символьного класса символ точка соответствует любому (в том числе и непечатному, бинарному) символу, кроме символа перевода строки '\n'. В случае, если модификатор PCRE_DOTALL используется, точка соответствует также символу перевода строки. Обработка метасимвола "точка", никак не связана с метасимволами начала и конца строки, единственное, что у них общего,- так это специальное отношение к символу перевода строки. Внутри символьного класса точка не имеет специального значения.

### Квадратные скобки

Открывающая квадратная скобка объявляет начало символьного класса, завершаемого закрывающей квадратной скобкой. Символ ']' не имеет специального значения, и в случае, если закрывающая квадратная скобка необходима как член символьного класса, она должна быть первым символом непосредственно после открывающей квадратной скобки (если используется метасимвол '^', то непосредственно после него), либо экранироваться при помощи обратного слеша.

Символьный класс соответствует одиночному символу обрабатываемой строки, причем сам символ должен содержаться в наборе, определяемым классом. В случае, если первым символом описания класса является '^', логика работы инвертируется: класс соответствует одиночному символу, который не содержится в наборе, определяемым классом. Если символ '^' необходим как член класса, его не следует помещать первым символом в описании класса либо необходимо экранировать при помощи обратного слеша.

К примеру, символьный класс [aeiou] соответствует любой гласной букве в нижнем регистре, в то время, как [^aeiou] соответствует любому символу, не являющемуся гласной буквой нижнего регистра. Следует понимать, что символ '^' всего лишь удобный инструмент для описания символов, не используемых в сопоставлении.

В случае, если производится регистронезависимое сопоставление, любая буква символьного класса соответствует как своему верхнему, так и нижнему регистру. Таким образом символьный класс [aeiou] соответствует как 'A', так и 'a'. Аналогично, класс [^aeiou] не соответствует ни 'A', ни 'a'.

Внутри символьного класса символ перевода строки "\n" не имеет специального значения, независимо от наличия модификаторов PCRE_DOTALL и PCRE_MULTILINE. Символьные классы, построенные на отрицании, например [^a], соответствуют символу перевода строки.

Символ минус '-' внутри класса используется для задания символьного диапазона. Например, [d-m] соответствует любому символу, находящемуся между 'd' и 'm', включая сами символы 'd' и 'm'. В случае, если '-' необходим, как член класса, он должен находиться в такой позиции, в которой он не может интерпретироваться как диапазон (как правило, это первый и последний символ описания класса) либо экранироваться при помощи обратного слеша.

Недопустимо использовать закрывающую квадратную скобку в качестве границы символьного диапазона. К примеру шаблон '[W-]46]' будет интерпретирован как символьный класс, состоящий из двух символов ("W" и "-"), за которыми следует строка "46]", таким образом шаблон будет соответствовать строкам "W46]" или "-46]". Чтобы все же использовать символ ']' в описании диапазона, его необходимо экранировать при помощи обратного слеша, к примеру шаблон [W-\]46] будет интерпретирован как символьный класс, состоящий из символьного диапазона вместе с двумя последующими символами '4' и '6'. Такого же результата можно достичь используя шестнадцатиричное или восьмеричное представление символа ']'.

Для построения символьных диапазонов используется ASCII представление символов. Таким образом пограничные символы можно задавать непосредственно в числовом представлении, например, [\000-\037]. В случае, если выполняется регистронезависимый поиск, символы, описанные в диапазоне, также будут соответствовать символам обеих регистров. К примеру, диапазоны [W-c] и [][\^_`wxyzabc] эквивалентны (в случае регистронезависимого поиска). Например, если установлена локаль "fr" (Франция) необходимо использовать [\xc8-\xcb] для задания соответствия ударному 'E' в обоих регистрах.

Общие типы символов \d, \D, \s, \S, \w, и \W также могут использоваться в символьных классах, добавляя при этом в класс те символы, которым соответствуют. Например, класс [\dABCDEF] соответствует любой шестнадцатиричной цифре. Символ '^' может использоваться совместно с общим типом, взятым в верхнем регисте, для указания более узкого набора символов. Например, класс [^\W_] соответствует любой букве или цифре, но не символу подчеркивания.

Все неалфавитные символы, кроме \, -, ^ (вначале) и завершающего ']', не являются специальными символами, но использование экранирующего слеша перед ними не навредит.

### Вертикальная черта

Символ вертикальной черты '|' используются для разделения альтернативных масок. Например шаблон `gilbert|sullivan` соответствует как "gilbert" так и "sullivan". Допустимо указывать любое количество альтернатив, также допустимо указывать пустые альтернативы (соответствуют пустой строке). В процессе поиска соответствия просматриваются все перечисленные альтернативы слева направо, останавливаясь после первого найденного соответствия. В случае, если альтернативные варианты перечислены в подшаблоне, то поиск соответствия означает нахождение соответствия одному из альтернативных вариантов подмаски и остатку основного шаблона.

### Установка внутренних опций

Установки PCRE_CASELESS, PCRE_MULTILINE, PCRE_DOTALL и PCRE_EXTENDED могут быть локально предопределены в шаблоне с использованием специальных символьных Perl-последовательностей, заключенных между символами "(?" и ")".

Таблица 1. Символы внутренних опций

`i` | for PCRE_CASELESS
`m` | для PCRE_MULTILINE
`s` | для PCRE_DOTALL
`x` | для PCRE_EXTENDED

Например, (?im) указывает на регистронезависимый, многострочный режим поиска. Также можно сбросить опцию, поставив перед ней символ '-', либо комбинировать установку и отмену режимов. Например, (?im-sx) устанавливает флаги PCRE_CASELESS, PCRE_MULTILINE и отменяет флаги PCRE_DOTALL и PCRE_EXTENDED. В случае, если опциональный символ расположен непосредственно после либо перед символом '-', опция будет отменена.

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

(?i)abc
a(?i)bc
ab(?i)c
abc(?i)

, что, в свою очередь равносильно компиляции шаблона 'abs' с указанием модификатора PCRE_CASELESS. Другими словами, такие установки верхнего уровня применяются ко всему шаблону (если отсутствуют дополнительные модификаторы в подмасках). Если присутствуют несколько опций верхнего уровня, будет использована самая правая опция.

В случае, если опция встречается в подмаске, эффект может быть разным. В Perl 5.005 была добавлена следующая особенность: опция внутри подмаски влияет только на ту часть подмаски, которая идет после указания опции. Таким образом `(a(?i)b)c` соответствует исключительно строкам 'abc' и 'aBc' (предполагается, что модификатор PCRE_CASELESS не используется). Это означает, что cуществует возможность указывать различные наборы опций для отдельных участков шаблона. Применение опций в одной из альтернативных веток также распространяется на все последующие ветки. Например: `(a(?i)b|c)` соответствует "ab", "aB", "c" и "C", хотя при совпадении с "C" первая ветвь покидается до установки опции. Это объясняется тем, что установка всех опций происходит на этапе компиляции шаблона.

Опции, специфичные для PCRE, такие как PCRE_UNGREEDY и PCRE_EXTRA могут быть установлены точно так же, как и Perl-совместимые опции, путем использования символов U и X соответственно. Флаг (?X) специфичен тем, что должен быть расположен в шаблоне прежде, чем будет использоваться любая другая дополнительная возможность, даже если он расположен на верхнем уровне. Лучше всего размещать флаг (?X) в самом начале шаблона.

### Подмаски

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

1. Локализирует набор альтернатив. Например, шаблон `cat(aract|erpillar|)` соответствует одному из слов "cat", "cataract" или "caterpillar". Без использования скобок он соответствовал бы строкам "cataract", "erpillar" или пустой строке.

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

Например, если строка "the red king" сопоставляется с шаблоном `the ((red|white) (king|queen))`, будут захвачены подстроки "red king", "red" и "king", и их номера соответственно 1, 2 и 3.

На самом деле выполнение одновременно двух функций не всегда удобно. Бывают случаи, когда необходима группировка альтернатив без захвата строки. В случае, если после открывающей круглой скобки следует "?:", захват строки не происходит, и текущая подмаска не нумеруется. Например, если строка "the white queen" сопоставляется с шаблоном `the ((?:red|white) (king|queen))`, будут захвачены подстроки "white queen" и "queen", и они будут пронумерованы 1 и 2 соответственно. Максимальное количество захватывающих подмасок - 99, максимальное количество всех подмасок - 200.

В случае, если в незахватывающей подмаске необходимо указать дополнительные опции, можно воспользоваться удобным сокращением: символ, обозначающий устанавливаемую опцию помещается между "?" и ":". Таким образом, следующие два шаблона

(?i:saturday|sunday)
(?:(?i)saturday|sunday)

соответствуют одному и тому же набору строк. Поскольку альтернативные версии берутся слева направо, и установленные опции сохраняют свое действие до конца подмаски, опция, установленная в одной ветке, также имеет эффект во всех последующих ветках. Поэтому приведенные выше шаблоны совпадают как с "SUNDAY", так и с "Saturday".

### Повторение

Повторение задается при помощи квантификаторов, следующих за любым из указанных ниже элементов:

- произвольным, возможно экранированным, символом

- метасимволом "точка"

- символьным классом

- ссылкой на предыдущий фрагмент шаблона (см. следующий раздел)

- взятой в круглый скобки подмаской (если это не утверждение - см. далее)

Общий квантификатор повторения указывает минимальное и максимальное допустимое количество совпадений, согласно двум числам, заключенными в фигурные скобки и разделенными запятой. Числа должны быть меньше чем 65536, и первое число не должно превышать второе по значению. Например: `z{2,4}` соответствует "zz", "zzz" или "zzzz". Закрывающая фигурная скобка сама по себе не является специальным символом. В случае, если второе число опущено, но запятая присутствует, нет верхнего предела; в случае, если и второе число и запятая опущены, требуется точное число повторений. Таким образом `[aeiou]{3,}` соответствует как минимум трем последовательным гласным (а также любому их количеству выше трех), в то время как `\d{8}` соответствует исключительно восми цифрами. Открывающая фигурная скобка, расположенная в недопустимой для квантификатора позиции, либо не соответствующая синтаксису квантификатора, интерпретируется как обыкновенная символьная строка. Например, {,6} не является квантификатором, а интерпретируется как символьная строка из четырех символов.

Квантификатор {0} является допустимым и ведет себя таким образом, будто бы сам квантификатор и предшествующий ему элемент отсутствуют.

Для удобства (а так же обратной совместимости) три наиболее распространённых квантификатора имеют односимвольные аббревиатуры:

Таблица 2. Односимвольные квантификаторы

`*` | эквивалентен `{0,}`
`+` | эквивалентен `{1,}`
`?` | эквивалентен `{0,1}`

Можно конструировать бесконечные циклы, указав после шаблона, не содержащегося в заданной строке, квантификатор, не имеющий верхнего предела, например: `(a?)*`

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

По умолчанию, все квантификаторы являются "жадными", это означает, что они совпадают максимально возможное количество раз (но не более, чем максимально допустимое количество раз), не приводя к невозможности сопоставления остальных частей шаблона. Классический пример проблем, которые могут возникнуть в связи с такой особенностью квантификаторов - нахождение комментариев в C-программах. Комментарием считается произвольный текст, находящийся внутри символьных комбинаций /* и */ (при этом, символы '/' и '*' также могут быть частью комментария). Попытка найти комментарии при помощи шаблона `/\*.*\*/` в строке `/* первый комментарий */ не комментарий /* второй комментарий */` закончится неудачей, поскольку указанный шаблон соответствует всей строке целиком (из-за жадности кватификатора '*').

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

В случае, если установлена опция PCRE_UNGREEDY (отсутствующая в Perl), квантификаторы являются не жадными по умолчанию, но могут становиться жадными, если за ними следует символ '?'. Говоря другими словами, знак вопроса инвертирует жадность квантификаторов.

В случае, если используется подмаска с квантификатором, для которого задано минимальное количество повторений (больше одного), либо если задано максимальное количество повторений, для откомпилированного шаблона требуется больше памяти (пропорционально миниму либо максимуму соответственно).

В случае, если шаблон начинается с .* либо .{0,}, и установлен модификатор PCRE_DOTALL (являющийся аналогом Perl-опции /s), который позволяет метасимволу "точка" соответствовать переводу строки, шаблон неявно заякоривается. Это происходит поскольку все последующие конструкции будут сопоставляться с каждой символьной позицией в обрабатываемом тексте, и, как следствие, начало строки - единственная позиция, дающая наиболее полное совпадение. PCRE рассматривает каждый такой шаблон, как если бы ему предшествовала последовательность `\A`. В случае, если известно, что данные не содержат переводов строк, а сам шаблон начинается на .*, рекомендуется использовать PCRE_DOTALL для оптимизации шаблона, либо использовать метасимвол '^' для указания явного заякоривания.

В случае, если захватывающая подмаска повторяется, результирующим значением подмаски будет подстрока, совпадающая с результатом последней итерации. Например, после того, как `(tweedle[dume]{3}\s*)+` совпадет с "tweedledum tweedledee", результирующим значением подмаски будет "tweedledee". Однако, если присутствуют вложенные захватывающие подмаски, соответствующие значения могут быть установлены в предыдущих итерациях. Например, после того, как `/(a|(b))+/` совпадет с "aba", значением второй захваченной подстроки будет "b".

### Обратные ссылки

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

Однако, в случае, если следующее за обратным слешем число меньше 10, оно всегда интерпретируется как обратная ссылка, и приводит к ошибке только в том случае, если нет соответствующего числа открывающих скобок. Другими словами, открывающие скобки не обязаны предшествовать ссылке для чисел меньше 10. Более детальную информацию об обработке слеша, за которым следуют цифры, можно найти в разделе "Обратный слеш".

Обратная ссылка сопоставляется с частью строки, захваченной соответствующей подмаской, но не с самой подмаской. Таким образом шаблон `(sens|respons)e and \1ibility` соответствует "sense and sensibility", "response and responsibility", но не "sense and responsibility". В случае, если обратная ссылка обнаружена во время регистрозависимого поиска, то при сопоставлении обратной ссылки регистр также учитывается. Например, `((?i)rah)\s+\1` соответствует "rah rah" и "RAH RAH", но не "RAH rah", хотя сама подмаска сопоставляется без учета регистра.

На одну и ту же подмаску может быть несколько ссылок. Если подмаска не участвовала в сопоставлении, то сопоставление со ссылкой на нее всегда терпит неудачу. Например, шаблон `(a|(bc))\2` терпит неудачу, если находит соответствие с "a" раньше, чем с "bc". Поскольку может быть до 99 обратных ссылок, все цифры, следующие за обратным слешем, рассматриваются как часть потенциальной обратной ссылки. Если за ссылкой должна следовать цифра, необходимо использовать ограничитель. В случае, если указан флаг PCRE_EXTENDED, ограничителем может быть любой пробельный символ. В противном случае можно использовать пустой комментарий.

Ссылка на подмаску, внутри которой она расположена, всегда терпит неудачу, если это первое сопоставление текущей подмаски. Например, шаблон (a\1) не соответствует ни одной строке. Но все же такие ссылки бывают полезны в повторяющихся подмасках. Например, шаблон `(a|b\1)+` совпадает с любым количеством "a", "aba", "ababaa"... При каждой итерации подмаски обратная ссылка соответствует той части строки, которая была захвачена при предыдущей итерации. Чтобы такая конструкция работала, шаблон должен быть построен так, чтобы при первой итерации сопоставление с обратной ссылкой не производилось. Этого можно достичь, используя альтернативы (как в предыдущем примере) либо квантификаторы с минимумом, равным нулю.

### Утверждения

Утверждения - это проверки касательно символов, идущих до или после текущей позиции сопоставления, ничего при этом не поглощая (никакие символы исходного текста не ставятся в соответствие утверждениям). Наиболее простые варианты утверждений, такие как \b, \B, \A, \Z, \z, ^ и $ были рассмотрены ранее. Более сложные утверждения записываются как подмаски. Утверждения бывают двух видов: те, которые анализируют текст, предшествующий текущей позиции, и идущий после нее.

Сопоставление подмаски, содержащий утверждение, происходит обычным образом, за исключением того, что текущая позиция не изменяется. Утверждения касательно последующего текста начинаются с (?= для положительных утверждений и с (?! для отрицающих утверждений. Например, `\w+(?=;)` совпадает со словом, за которым следует символ ';', но при этом сама точка с запятой в совпадение не включается. А `foo(?!bar)` соответствует любому появлению "foo", после которого не идёт "bar". Заметим, что похожий шаблон `(?!foo)bar` не будет искать вхождение "bar", которому предшествует любая строка за исключением "foo". Но, тем не менее, он будет соответствовать любым вхождениям подстроки "bar", поскольку условие (?!foo) всегда `TRUE`, если следующие три символа - "bar". Для получения желаемого результата необходимо воспользоваться второй категорией утверждений.

Утверждения касательно предшествующего текста начинаются с (?<= для положительных утверждений и (?<! для отрицающих. Например, `(?<!foo)bar` не найдёт вхождения "bar", которым не предшествует "foo". Сами утверждения 'назад' ограничены так, чтобы все подстроки, которым они соответствуют, имели фиксированную длину. Но, в случае, если используются несколько альтернатив, они не обязаны иметь одинаковую длину. Таким образом шаблон `(?<=bullock|donkey)` корректен, но `(?<!dogs?|cats?)` вызовет ошибку во время компиляции. Ветки, которые соответствуют строкам разной длины, разрешены только на верхнем уровне утверждений касательно предшествующего текста. Это расширение относительно Perl 5.005, который требует чтобы все ветки соответствовали строкам одинаковой длины. Такое утверждение как `(?<=ab(c|de))` не корректно, поскольку верхний уровень маски может соответствовать строкам разной длины, но его можно преобразовать к корректному шаблону, используя альтернативы на верхнем уровне: `(?<=abc|abde)`. Утверждения касательно предшествующего текста реализованы так, что для каждой альтернативы текущая позиция временно переносится назад, на фиксированную ширину, после чего выполняется поиск соответствия условию. В случае, если перед текущей позицией недостаточно символов, поиск соответствия терпит неудачу. Утверждения назад в сочетании с однократными подмасками могут быть особенно удобны для поиска в конце строки; соответствующий пример приведен в конце раздела "Однократные подмаски".

Несколько утверждений (разных типов) могут присутствовать в утверждении, например: `(?<=\d{3})(?<!999)foo` совпадает с подстрокой "foo", которой предшествуют три цифры, отличные от "999". Следует понимать, что каждое из утвержений проверяется относительно одной и той же позиции в обрабатываемом тексте. Вначале выполняется проверка того, что предшествующие три символа - это цифры, затем проверяется, чтобы эти же цифры не являлись числом 999. Приведенный выше шаблон не соответствует подстроке "foo", которой предшествуют шесть символов, первые три из которых - цифры, а последние три не образуют "999". Например, он не соответствует строке "123abcfoo", в то время как шаблон `(?<=\d{3}...)(?<!999)foo` - соответствует. В этом случае анализируются предшествующие шесть символов на предмет того, чтобы первые три из них были цифрами, а последние три не образовали "999".

Утверждения могут быть вложенными, причем в произвольных сочетаниях: `(?<=(?<!foo)bar)baz` соответствует подстроке "baz", которой предшествует "bar", перед которой, в свою очередь, нет "foo", а `(?<=\d{3}(?!999)...)foo` - совершенно другой шаблон, соответствующий подстроке "foo", которой предшествуют три цифры и три произвольных символа, отличных от "999".

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

В утверждениях обрабатывается не более, чем 200 захватывающих подмасок.

### Однократные подмаски

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

В качестве примера, рассмотрим шаблон \d+foo в применении к строке `123456bar`

После того, как \d+ будет сопоставлен с первыми шестью цифрами, сопоставление "foo" потерпит неудачу. После этого, в соответствие \d+, будет сопоставлено 5 цифр, после очередной неудачи будет сопоставлено 4 цифры и так далее. В конце концов весь шаблон потерпит неудачу. Однократные подмаски указывают, что если одна часть шаблона была сопоставлена, ее не стоит анализировать повторно. Применимо к приведенному выше примеру весь шаблон потерпел бы неудачу после первого же неудачного сопоставления с "foo". Записываются однократные шаблоны при помощи круглых скобок следующим образом: (?>. Например: `(?>\d+)bar`

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

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

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

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

Однократные подмаски могут использоваться совместно с утверждениями касательно предшествующего текста для описания эффективных сопоставлений в конце обрабатываемого текста. Рассмотрим простой шаблон `abcd$` в применении к длинному тексту, который не соответствует указанной маске. Поскольку поиск происходит слева направо, вначале PCRE будет искать букву "a", и только потом анализировать следующие записи в шаблоне. В случае, если шаблон указан в виде `^.*abcd$`. В таком случае вначале .* сопоставляется со всей строкой, после чего сопоставление терпит неудачу (так как нет последующего символа 'a'). После чего .* сопоставляется со всей строкой, кроме последнего символа, потом кроме двух последних символов, и так далее. В конечном итоге поиск символа 'a' происходит по всей строке. Однако, если шаблон записать в виде: `^(?>.*)(?<=abcd)` повторный анализ для .* не выполняется, и, как следствие, может соответствовать только всей строке целиком. После чего утверждение проверяет последние четыре символа на совпадение с 'abcd', и в случае неудачи все сопоставление терпит неудачу. Для больших объемов обрабатываемого текста этот подход имеет значительный выигрыш во времени выполнения.

Если шаблон содержит неограниченное повторение внутри подмаски, которая в свою очередь также может повторяться неограниченное количество раз, использование однократных подмасок позволяет избегать многократных неудачных сопоставлений, которые длятся достаточно продолжительное время. Шаблон `(\D+|<\d+>)*[!?]` соответствует неограниченному количеству подстрок, которые состоят не из цифр, либо из цифр заключенных в <>, за которыми следует ? либо !. В случае, если в обрабатываемом тексте содержатся соответствия, время работы регулярного выражения будет невелико. Но если его применить к строке `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` это займет длительное время. Это связанно с тем, что строка может быть разделена между двумя частями шаблона многими способами, и все они будут опробованы (в примере мы использовали [?!], поскольку в случае одиночного символа в конце шаблона и PCRE и Perl выполняют оптимизацию. Они запоминают последний одиночный символ и в случае его отсутствия выдают неудачу). Если изменить шаблон на `((?>\D+)|<\d+>)*[!?]`, нецифровые последовательности не могут быть разорваны, и невозможность сопоставления обнаруживается гораздо быстрее.

### Условные подмаски

В PCRE реализована возможность подчинять шаблон условию либо выбирать из двух условных подмасок в зависимости от успеха сопоставления предыдущей подмаски. Условные подмаски имеют две допустимые формы использования:

(?(condition)yes-pattern)
(?(condition)yes-pattern|no-pattern)

В случае успешного сопоставления условия condition, используется подмаска yes-pattern, в противном случае no-pattern (если он присутствует). Если указано более двух альтернатив, возникнет ошибка во время компиляции.

Условия бывают двух видов. В случае, если между скобками заключены цифры, условие будет выполняться в том случае, если подмаска с соответствующим номером была успешно сопоставлена. Рассмотрим следующий шаблон (он содержит незначащий пробел для удобства чтения, подразумевается использование модификатора PCRE_EXTENDED), разделив его для удобства на три смысловые части: `( \( )? [^()]+ (?(1) \) )`

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

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

(?(?=[^a-z]*[a-z])
\d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} )

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

### Комментарии

Служебная последовательность (?# обозначает начало комментария, который продолжается до ближайшей закрывающей скобки. Вложенные скобки не допускаются. Символы, находящиеся внутри комментария, не принимают участия в сопоставлении шаблона.

В случае, если используется модификатор PCRE_EXTENDED, неэкранированный символ '#' вне символьного класса также означает начало блока комментария, который длится до конца текущей строки.

### Рекурсивные шаблоны

Рассмотрим задачу поиска соответствия со строкой, находящихся внутри неограниченного количества круглых скобок. Без использования рекурсии лучшее, что можно сделать - написать шаблон, который будет решать задачу для некоторой ограниченной глубины вложенности, так как обработать неограниченную глубину не предоставляется возможным. В Perl 5.6 предоставлены некоторые экспериментальные возможности, которые в том числе позвояляют реализовать рекурсию в шаблонах. Специально обозначение (?R) используется для указания рекурсивной подмаски. Таким образом, приведем PCRE шаблон, решающий поставленную задачу (подразумевается, что используется модификатор PCRE_EXTENDED, незначащие пробелы игнорируются): `\( ( (?>[^()]+) | (?R) )* \)`

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

Приведенный пример шаблона использует вложенные неограниченные повторения, поэтому использование однократных шаблонов значительно ускоряет процесс сопоставления, особенно в случаях, когда строка не соответствует заданной маске. Например, если его применить к строке: `(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()`, то несоответствие будет обнаружено достаточно быстро. Но в случае, если однократные шаблоны не используются, сопоставление будет затягиваться на длительное время, так как существует множество способов разделения строки между квантификаторами + и *, и все они должны быть проверены, прежде чем будет выдано сообщение о неудаче.

Значение, устанавливаемое для захватывающей подмаски будет соответствовать значению, захваченному на наиболее глубоком уровне рекурсии. В случае, если приведенный выше шаблон сопоставляется со строкой `(ab(cd)ef)`, захваченным значением будет 'ef', которое является последним значением, принимаемым на верхнем уровне. В случае, если добавить дополнительные скобки `\( ( ( (?>[^()]+) | (?R) )* ) \)`, захваченным значением будет "ab(cd)ef". В случае, если в шаблоне встречается более, чем 15 захватывающих скобок, PCRE требуется больше памяти для обработки рекурсии, чем обычно. Память выделяется при помощи функции pcre_malloc, и освобождается соответственно функцией pcre_free. Если память не может быть выделена, сохраняются данные только для первых 15 захватывающих скобок, так как нет способа выдать ошибку out-of-memory изнутри рекурсии.

### Производительность

Некотрые элементы, которые могут встречаться в шаблонах, являются более эффективными, чем ряд других. Например, гораздо эффективней использовать символьный класс [aeiou] вместо набора альтернатив (a|e|i|o|u). Как правило, более простая конструкция является более эффективной. Книга Jeffrey Friedl'а содержит много обсуждений вопроса оптимизации регулярных выражений.

В случае, если шаблон начинается с .* и используется флаг PCRE_DOTALL, шаблон неявно заякоривается, так как он может совпадать только в начале строки. Но если PCRE_DOTALL не используется, PCRE не может выполнить соответствующую оптимизацию, так как в таком случае метасимвол '.' не соответствует символу начала строки (если обрабатываемые данные содержат переводы строк, такой шаблон может соответствовать шаблону не от начала строки, а от позиции непосредственно после перевода строки). Например, применяя шаблон `(.*) second` к строке "first\nand second" (где \n обозначает символ перевода строки), значение, захваченное первой подмаской, будет 'and'. Чтобы обработать все возможные точки соответствия, PCRE пытается сопоставить шаблон после каждого символа перевода строки.

В случае, если вы используете подобные шаблоны для обработки данных, не содержащих переводы строк, для лучшей производительности используйте модификатор PCRE_DOTALL, либо начинайте шаблон с ^.* для указания явного заякоривания. Это предотвратит PСRE от поиска символов новых строк и дополнительных попыток сопоставить шаблон с каждой такой найденной позицией.

Избегайте шаблонов, которые содержат вложенные неограниченные повторения. Сопоставление их со строками, не содержащими совпадений, занимает длительное время. Рассмотрим пример шаблона `(a+)*`

Он может соответствовать с "aaaa" 33-мя различными способами, и эта цифра очень быстро растет при увеличении строки. (В данном примере, квантификатор * может совпадать 0, 1, 2, 3 или 4 раза, и для каждого такого случая, кроме нуля, квантификатор + также может совпадать различное число раз.) Если остаток шаблона таков, что все совпадение терпит неуачу, PCRE должно попробовать все возможные варианты совпадения, что может потребовать огромного количества времени.

При помощи оптимизации можно отловить наиболее простые случаи, такие как `(a+)*b` где следом идёт литеральный символ. Прежде, чем производить стандартную процедуру поиска, PCRE проверяет в последующей подстроке наличие символа 'b', и, в случае отсутствия такового, попытка сопоставления немедленно завершается неудачей. Однако, когда последующего литерала нет, оптимизация не может быть применена. Вы можете ощутить разницу, сравнив поведение `(a+)*\d` с поведением приведенного выше шаблона. Первый определяет невозможность сопоставления практически сразу же, при сопоставлении со строкой состоящей из символов 'a', в то время как второй тратит длительное время на поиск в строках длинее 20 символов.

add a note User Contributed Notes
Синтаксис регулярных выражений
rn214 at cam dot ac dot uk
22-Jan-2007 07:17
`It isn't actually documented here, but patterns can begin with almost anything - you can choose the delimiter to suit. Normally, a pattern has the format: /rrr/ooo where the / denotes the beginning and ending of the regex" rrr", and "ooo" are some pattern modifiers.
However, as with perl, you can use any character in place of the slash. For example, @rrr@ooo is perfectly valid. The chosen character is autodetected.
The advantage of doing this is when / is a common character in your regex, and you don't want to keep escaping it with \/ .
For example, a regex to match "http://" would normally be: /http:\/\// , but it's easier to read as: @http://@`
theppg_001 at hotmail dot com
20-Nov-2006 01:22
`Hi there
This was originally made by someone eles but it didn't work correctly and so I remade it and as far as I know it works right.
<?php
/**
* strip_selected_tags ( string str [, string strip_tags[, strip_content flag]] )
* ---------------------------------------------------------------------
* Like strip_tags() but inverse; the strip_tags tags will be stripped, not kept.
* strip_tags: string with tags to strip, ex: "<a><p><quote>" etc.
* strip_content flag: TRUE will also strip everything between open and closed tag
*/
function strip_selected_tags($str, $tags = "", $stripContent = false)
{
preg_match_all("/<([^>]+)>/i", $tags, $allTags, PREG_PATTERN_ORDER);
$replace = "%(<$tag.*?>)(.*?)(<\/$tag.*?>)%is";
foreach ($allTags[1] as $tag) {
if ($stripContent) {
$str = preg_replace($replace,'',$str);
}
$str = preg_replace($replace,'${2}',$str);
}
return $str;
}
?>
Before I 'fixed' it, when running
strip_selected_tags("this is <p align=\"center\">a test</p> and <b>this is bold</b>","<p><b>")
You would get back
"this is <p align=\"center\">a test</p> and this is bold"
Why? Because it did not take into account that there could be options etc in the HTML Tag.
My one works perfectly when stripping just the tags or the tag and its contents too!
So now when you run
strip_selected_tags("this is <p align=\"center\">a test</p> and <b>this is bold</b>","<p><b>")
You get back
"this is a test and this is bold"
Or when running
strip_selected_tags("this is <p align=\"center\">a test</p> and <b>this is bold</b>","<p><b>",true)
You get back
"this is and "
Hope it helps someone :)`
sasq1 at go2 dot pl
19-Sep-2006 02:12
`Only a small correction to this regexp:
%&quot;(.+)&quot;[\s]+((http|https|ftp|file)://[^\s]+?)(.*)%sU
It's not necessary to write character class "[..]" if it only contains one character match. Instead of "[\s]+" you can write simply "\s+". The similar is for the character class "[^\s]+", which may be written as "\S+". The "\S" assertion matches all characters, that are NOT whitespace.
After those corrections we get a little shorter and easier to read regexp [if we can say that ANY regexp is easy to read at all ;-D ]:
%&quot;(.+)&quot;\s+((http|https|ftp|file)://\S+?)(.*)%sU
The only miserable thing with this regexp is that it matches patterns like:
"Some description" http://www.somepage.com/catalog/file.html
but doesn't match links like this one:
"Some description" www.somepage.com/catalog/file.html`
no at need dot to
31-Aug-2006 04:05
`function to strip urls from a string (case insensitive).
function stripUrls($str)
{
$pattern="%((http://|https://|ftp://|file://|www.)[^\s]+?)(.*)%isU";
$str=preg_replace($pattern,"",$str);
return $str;
}`
ufotds at yahoo dot com
29-May-2006 08:25
`Ok, I will try to explain the regex by davout. Most of this is explained above though, but if you are new to regex and just read all off the above, you probably deserved a practical one nicely dissected. I dissect it part by part...
%&quot;(.+)&quot;[\s]+((http|https|ftp|file)://[^\s]+?)(.*)%sU
% //this is a delimiter, basically saying to the parser that if it is found again, the expression stops.
&quot; //this is a html entity encoding, because in html quotes are like metacharacters, so they are escaped this way. see here for a table http://www.cookwood.com/entities/
( //this is the beginning of the first group, will later be referenced by $1, or (if referenced within the exp) \1, this doesn't happen here
. //matches any character... (normally except newline unless you set the s modifier in the end, which happens here, so it is anything including newline)
+ //... one or more times
) //end of first group
&quot; //same as above
[\s] //[]denotes a class, meaning that this place can hold any character from within the class, in this case it is a metacharacter signifying any whitespace character
+ //...again one or more of the last character
( //open the second group $2
(http|https|ftp|file) //the third group ($3) is an alteration, and can be any of these to fulfill a match.
:// //they just represent themselves literally
[^\s]+? //this is one or more none(^) whitespace characters, where the the quantifier is greedy this time, see the section on repetition above how it works, but basically we want the group to include the whole url, and because the next character (.*) matches anything, an ungreedy quantifier here would only match one character, because the .* would take over immeadiately.
) //close the second group
(.*) //$4 this basically consumes the rest of the string to put it back after we are done. As far as I can see, this last group is just redundant, as we don't replace this, we just put it back. Personally I would leave this away.
% //end of expression
s //make a . fit even newline
U //Reverses default to ungreedy, and +? or ?? or *? to greedy.
The groups are then used to replace the pattern and put these pieces back... So to make a long story short. you can write your link like "name" http://my.link bla bla bla. and it will be replaced by a real one.
So, that's how easy it is... Have fun`
bobbykjack at yahoo dot co dot uk
04-May-2006 12:53
`If anyone else out there is having a problem with the 'general repetition quantifier', please take heed of the note ", separated by a comma." (which should be rewritten ",separated ..." !) Specifically,
<?php
$pattern = '/z{2, 4}/';
?>
is NEVER what you want. Ensure there is no comma between the min and max values:
<?php
$pattern = '/z{2,4}/';
?>`
spook at op.pl
04-Apr-2006 11:37
`A useful note for beginners: note the difference between mathematical and PHP regular expressions. The _mathematical_ regex:
(a+b+c)*
which written in PHP syntax will look like:
[abc]*
will match any string built of a, b or c letters, but will not match string, for example:
abcd
However, the _PHP_ regular expression will match above string, because the regex means "accept all strings, which contain 0 or more occurences of letters: a, b or c".
To convert the regexp from the mathematical to PHP convention, use the ^ and $ characters, which indicate start and end of tested string. So the regexp:
^[abc]*$
means "match all strings, which, between its beginning and end, have 0 or more occurences of letters a, b or c" - which is, what we searched for.
Nasty habit, especially after two tests on "theoretical basics of computer science" :)`
michael(at)webstaa(dot)com
13-Dec-2005 06:21
`If you want to match any character other than reverse solidus (backslash), e.g.: to replace double single quotes in a string but not if they are preceeded by a backslash, try:
<?php
preg_replace ( "/[^\\x5c]''/", "null", $sql );
?>`
Daniel Vandersluis
23-Nov-2005 10:50
`Concerning note #6 in "Differences From Perl", the \G token *is* supported as the last match position anchor. This has been confirmed to work at least in preg_replace(), though I'd assume it'd work in preg_match_all(), and other functions that can make more than one match, as well.`
roland dot illig at gmx dot de
08-Nov-2005 01:02
`<quote>
9. Another as yet unresolved discrepancy is that in Perl 5.005_02 the pattern /^(a)?(?(1)a|b)+$/ matches the string "a", whereas in PCRE it does not. However, in both Perl and PCRE /^(a)?a/ matched against "a" leaves $1 unset.
</quote>
The last sentence does not indicate a bug. If the string "a" should match against the regular expression /^(a)?a/, the last "a" in the regex must be matched by any literal "a" in the string. The rest of the string is "", which obviously does not match the first /^(a)/.`
Toni
23-Sep-2005 12:47
`While andrew is right about using a parser when a parser is called for, I have to point out the fact, that the "regex killer" example he is giving is consistent with the general GIGO *(garbage in -> agrabe out) principle:. That said, the below mentioned regex will do exactly what it's supposed to do on it. Choke.
That type of code is not recommended by W3C. Although an xhtml document will validate, it will yield warnings. It is much safer to use "&lt;" in such a case. That would be <img class="match1" alt="&lt;">. The lesson here is "rfm". And for advanced users "RTFM".`
Andrew
05-Sep-2005 10:03
`wfinn, your example falls into one of the common traps, which is trying to parse a complicated language with a simple regex. Just try feeding it input containing a tag like <img class="match1" alt="<">. It'll die a horrible death. The main lesson here is "never parse HTML with a regex". The lesson for the advanced reader is "never use a regex where a parser is called for."`
davout_69 at yahoo dot com
22-Jul-2005 12:36
`Found a great expression that replaces a text url - http:/.... with <a href ="http://www...">
Although it works, I still don't understand how. If someone could explain this it would great to learn what amounts to me as a foreign language :-)
Here is the expression:
'%&quot;(.+)&quot;[\s]+((http|https|ftp|file)://[^\s]+?)(.*)%sU'
$pcre = '%&quot;(.+)&quot;[\s]+((http|https|ftp|file)://[^\s]+?)(.*)%sU';
if ( preg_match( $pcre, $lines ) ){
$lines = preg_replace( $pcre, '<a href="$2" target="_top">$1</a>$4', $lines );
} else {
$pcre = '%\b((http|https|ftp|file)://[^\s]+?)(.*)%U';
$lines = preg_replace( $pcre, '<a href="$1" target="_top">$1</a>$3', $lines );
}`
Ned Baldessin
16-Jul-2005 04:14
`Although \w and \W do include as "word characters" locale-specific characters (like "�" if you are using the "fr" locale), \b and \B do not work the same way.
For example :
"foo �tait bar" => /\W(�tait)\W/ => This captures correctly "�tait".
"foo �tait bar" => /\b(�tait)\b/ => This fails to capture it.
This is confusing, because the manual talks in both cases about "word characters", but fails to mention the difference in behaviour.`
wfinn at yakasha dot net
15-Jul-2005 12:22
`Some simple assertions so you only match inside (or outside) an html tag:
<?php
$string1 = "<b><span class=\"match1\">match2</span><span class=\"match3\">match4</span></b>match5";
$string2 = preg_replace( "/match(?![^<]*?>)/", "replacement", $string1 ); // Matches outside the html tag
$string3 = preg_replace( "/match(?=[^<]*?>)/", "replacement", $string1 ); // Matches inside the html tag
echo "1: " . str_replace(array("<",">"), array("&lt;","&gt;"), $string1) . "<br>\n";
echo "2: " . str_replace(array("<",">"), array("&lt;","&gt;"), $string2) . "<br>\n";
echo "3: " . str_replace(array("<",">"), array("&lt;","&gt;"), $string3) . "<br>\n";
?>
This outputs:
1: <b><span class="match1">match2</span><span class="match3">match4</span></b>match5
2: <b><span class="match1">replacement2</span><span class="match3">replacement4</span></b>replacement5
3: <b><span class="replacement1">match2</span><span class="replacement3">match4</span></b>match5`
june05 at tilo-hauke dot de
04-Jun-2005 11:24
`//to match quotings in code strings by skipping included quotings if they appear use this expression:
$matchQuotings='/(((?<!\\\)")((?<=\\\)"
|[^"])*((?<!\\\)"))
|(((?<!\\\)\')((?<=\\\)\'
|[^\'])*((?<!\\\)\'))
/';
// for example: matchQuotings finds:
// "javascript:func('string-param');"
// in strings like this:
// ... <a href="javascript:func('string-param')"> ...
// and finds:
// 'javascript:func("string-param");'
// in strings like this:
// ... <a href="javascript:func('string-param')"> ...
// and finds:
// 'a "b" c'
// "d 'e' f"
// in strings like this:
// ... x 'a "b" c' y "d 'e' f" z...`
xlex0x835 at rambler dot ru
15-May-2005 11:38
`Attention (it may saves you lot's of time): in this doc there is no words about Unicode operations in pcre_* functions, while it is very important.
Just read missing part (from http://www.pcre.org/pcre.txt):
==================
In UTF-8 mode, characters with values greater than 128 never match \d,
\s, or \w, and always match \D, \S, and \W. This is true even when Uni-
code character property support is available.
==================
What to do:
==================
Unicode character properties
When PCRE is built with Unicode character property support, three addi-
tional escape sequences to match generic character types are available
when UTF-8 mode is selected. They are:
\p{xx} a character with the xx property
\P{xx} a character without the xx property
\X an extended Unicode sequence
The property names represented by xx above are limited to the Unicode
general category properties. Each character has exactly one such prop-
erty, specified by a two-letter abbreviation. For compatibility with
Perl, negation can be specified by including a circumflex between the
opening brace and the property name. For example, \p{^Lu} is the same
as \P{Lu}.
If only one letter is specified with \p or \P, it includes all the
properties that start with that letter. In this case, in the absence of
negation, the curly brackets in the escape sequence are optional; these
two examples have the same effect:
\p{L}
\pL
The following property codes are supported:
C Other
Cc Control
Cf Format
Cn Unassigned
Co Private use
Cs Surrogate
L Letter
Ll Lower case letter
Lm Modifier letter
Lo Other letter
Lt Title case letter
Lu Upper case letter
M Mark
Mc Spacing mark
Me Enclosing mark
Mn Non-spacing mark
N Number
Nd Decimal number
Nl Letter number
No Other number
P Punctuation
Pc Connector punctuation
Pd Dash punctuation
Pe Close punctuation
Pf Final punctuation
Pi Initial punctuation
Po Other punctuation
Ps Open punctuation
S Symbol
Sc Currency symbol
Sk Modifier symbol
Sm Mathematical symbol
So Other symbol
Z Separator
Zl Line separator
Zp Paragraph separator
Zs Space separator
Extended properties such as "Greek" or "InMusicalSymbols" are not sup-
ported by PCRE.
Specifying caseless matching does not affect these escape sequences.
For example, \p{Lu} always matches only upper case letters.
The \X escape matches any number of Unicode characters that form an
extended Unicode sequence. \X is equivalent to
(?>\PM\pM*)
That is, it matches a character without the "mark" property, followed
by zero or more characters with the "mark" property, and treats the
sequence as an atomic group (see below). Characters with the "mark"
property are typically accents that affect the preceding character.
Matching characters by Unicode property is not fast, because PCRE has
to search a structure that contains data for over fifteen thousand
characters. That is why the traditional escape sequences such as \d and
\w do not use Unicode properties in PCRE.
==================`
onerob at gmail dot com
01-Apr-2005 04:51
`If, like me, you tend to use the /U pattern modifier, then you will need to remember that using ? or * to to test for optional characters will match zero characters if it means that the rest of the pattern can continue matching, even if the optional characters exist.
For instance, if we have this string:
a___bcde
and apply this pattern:
'/a(_*).*e/U'
The whole pattern is matched but none of the _ characters are placed in the sub-pattern. The way around this (if you still wish to use /U) is to use the ? greediness inverter. eg,
'/a(_*?).*e/U'`
karoly at negyesi dot network dot i dot mean dot net
10-Mar-2005 02:05
`The PCRE in 4.3 has a lot more features. Read http://www.zend.com/lists/php-dev/200306/msg00844.html`
W W W
07-Mar-2005 07:22
`Back references are a great way to achieve exact matching when it would have been impossible any other way. Take these three strings.
1) "www.www.com"
2) 'www.www.com'
3) "www.www.com'
The regex /^("|').+?("|')$/ would match all three strings but what if you needed the 3rd string above to be illegal because the quotes are not the same? You could write four different regexes to check for every possible case OR you could use back references.
/^("|').+?\1$/ will match strings 1 and 2 but not string 3. Try this code for further proof:
$str_test="'www.www.com\"";
$int_count=preg_match("/^(\"|').+?\\1$/", $str_test, $matches, PREG_OFFSET_CAPTURE);
The preg_match function will not match against $str_test because the quotes are mismatched. If you change $str_test to
$str_test = "'www.www.com'";
the preg_match will work.`
SG_01[-at-]sg01[-dot-]net
10-Feb-2005 09:24
`Re: info at atjeff dot co dot nz
It's very simple actually, the question mark acts as a quantity minimizer. Which means it won't take up as much space as it can for one "tag". The same can be achieved by putting a U after the ending slash.
Like this:
<?PHP
function Simple_Tag_Decode($Data, $Tag) {
return preg_replace("/&gt;$Tag&lt;(.*)&gt;\/$Tag&lt;/iU", "<$Tag>\\1</$Tag>", $Data);
}
?>`
info at atjeff dot co dot nz
07-Feb-2005 04:46
`ive never used regex expressions till now and had loads of difficulty trying to convert a [url]link here[/url] into an href for use with posting messages on a forum, heres what i manage to come up with:
$patterns = array(
"/\[link\](.*?)\[\/link\]/",
"/\[url\](.*?)\[\/url\]/",
"/\[img\](.*?)\[\/img\]/",
"/\[b\](.*?)\[\/b\]/",
"/\[u\](.*?)\[\/u\]/",
"/\[i\](.*?)\[\/i\]/"
);
$replacements = array(
"<a href=\"\\1\">\\1</a>",
"<a href=\"\\1\">\\1</a>",
"<img src=\"\\1\">",
"<b>\\1</b>",
"<u>\\1</u>",
"<i>\\1</i>"
);
$newText = preg_replace($patterns,$replacements, $text);
at first it would collect ALL the tags into one link/bold/whatever, until i added the "?" i still dont fully understand it... but it works :)`
pilot doofy at gmail d0t k0m
04-Jan-2005 08:33
`Keep in mind that when using limits whitespace doesn't count. I made this mistake quite often. Remember the [[:space:]] character set. In example:
$string = "Wow php is really cool";
eregi("[[:alpha:]]{18}", $string); //returns true but
eregi("[[:alpha:]]{22}", $string); // does not return true because the whitespace doesn't count for matches`
J Daugherty
09-Dec-2004 09:06
`In the character class meta-character documentation above, the circumflex (^) is described:
"^ negate the class, but only if the first character"
It should be a little more verbose to fully express the meaning of ^:
^ Negate the character class. If used, this must be the first character of the class (e.g. "[^012]").`
29-May-2004 02:15
`In addition to the meta-characters mentioned above, there can be another special character in a regular expression: the delimiter you use to start and end your expression. Often people use the / character for this.
For example, if you wanted to search for text surrounded by opening and closing tags like'<TD>SELL</TD>' and replace it with nothing (erase it), you might be tempted to use a regex like this:
<?php
$myNewText = preg_replace('/<TD>SELL</TD>/', "", $myText);
?>
This does not work properly. As mentioned in the Introduction at the top of http://www.php.net/manual/en/ref.pcre.php, if the delimiter appears in the middle of your regular expression, then you must put a \ character before it. So this DOES work:
<?php
$myNewText = preg_replace('/<TD>SELL<\/TD>/', "", $myText);
?>
That same Introduction also mentions that you can start and end your expression with characters other than the usual /. Because there are no % characters in the middle of my expression above, I might prefer to use the following:
<?php
$myNewText = preg_replace('%<TD>SELL</TD>%', "", $myText);
?>
That also works correctly, and I did not need a \ before the /.`
napalm at spiderfish dot net
17-Mar-2004 08:14
`Pay attention that some pcre features such as once-only or recursive patterns are not implemented in php versions prior to 5.00
Napalm`
brewthatistrue
02-Mar-2004 07:06
`http://zvon.org/other/PerlTutorial/Output/index.html`
gphemsley at users dot sourceforge dot net
05-Dec-2003 11:53
`Another good website for Regular Expression reference materials is:
http://www.regularexpressions.info/`
brett_hegr at yahoo dot com
18-Nov-2003 11:39
`This is a gem of a website. It has a big library of useful expressions, a search engine, and a tool for testing your regexp.
http://www.regexlib.com/`
add a note
preg_grep Модификаторы шаблонов

Last updated: Fri, 26 Jan 2007
show source | credits | stats | sitemap | contact | advertising | mirror sites
Copyright © 2001-2007 The PHP Group
All rights reserved.
This mirror generously provided by: Yahoo! Inc.
Last updated: Sat Mar 10 10:36:09 2007 PST