Учебник по основам PHP

         

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


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

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

/шаблон/модификаторы

Ограничителями могут служить: прямые слеши «/», а также любые не алфавитно-цифровые символы, кроме обратного слеша «\». Часто в качестве ограничителей служат символы: \, %, $. Завершающий ограничитель должен быть представлен тем же символом, что и начинающий; ограничитель должен быть первым символом регулярного выражения. Если необходимо использовать символ, выбранный ограничителем в шаблоне, ему должен предшествовать обратный слеш «\» (например: «/\d{l,2}V\d{2}/»).

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

Sbegin = "OOps"; Spattern = "/Sbegnn/".

Теперь шаблон Spattern будет искать последовательность Oops в любом месте текста вместо ожидаемого фрагмента begin в начале текста. В данном случае строку следует записывать как Spattern = "ASbegin/"; либо как: Spattern = '/$begin/':. Подобных примеров можно привести множество, поэтому не брезгуйте заглянуть в раздел «Типы: Строки», чтобы вспомнить, как РНР интерпретирует строки, и, в частности, как следует использовать слеши.

Синтаксис шаблона

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



Метасимвол Значение
\ подстановка;
. любой символ: [*\n] или [\0-\xFF];
I альтернатива;
0 ограничители подшаблона;
|] ограничители класса символов;
{} числители повторения «от X до У раз»;
? числитель «1 или 0 раз»; или мишшизатор числителя; или расширение значения метасимвола «(»;
* числитель «0 или более pa:i>>;
+ числитель «1 или более раз»;
< претензия «в начале строки»;
$ претензия «в конце строки».

В классах символов метасимволом является знак диапазона «минус» (-), а метасимвол инвертирует класс методом «все символы, кроме указанных».

Обычно пробелы в шаблоне рассматриваются как значащие. При установке же модификатора х все пробелы в шаблоне и все символы от знака # и до конца строки воспринимаются как комментирующие. Тем не менее, в классах символов пробел и знак # всегда являются значащими. В маркерах специальных подшаблонов не допускается использование пробелов, так как тогда нарушается смысл маркеров (сравните: (?<= ххх) и (? < = ххх)).

Например, шаблон (неплохой пример, хотя он и неадекватно работает с одинаковыми вложенными тегами):

'% < ([*> ]+) (['>]*) > # открывающий тег (и атрибуты тега) (.*) # содержимое тега < / \1 > # закрывающий тег £xis'

эквивалентен шаблону:

'*<(Г> ]+)(Г>]*)>(.*Н?#содержимое Tera)</\l>*is'

Далее рассматриваются способы использования метасимволов.

Подстановки

Символ (\) помимо операций подстановки, рассмотренных ниже, используется для превращении метасимволов в обычные. Например, для того, чтобы использовать точку в шаблоне как «точку», а не как «оператор подстановки любого символа», перед ней следует ставить слеш (\). Так же желательно поступать со всеми спецсимволами (то есть не являющимися буквенно-цифровыми), даже если они и не являются метасимволами. (При установленном модификаторе х слешем также следует предварять пробел и символ #, если только они не обозначают комментарий.)

Подстановки, обозначаемые символом обратного слеша (\), бывают пяти видов.

1. Подстановка непечатного символа.

Вместо следующих последовательностей вставляется:

  • \а - символ BEL (07 в ASCII);
  • \е — символ escape (hex IB в ASCII);
  • \f — символ прогонки страницы formfeed (hex ОС в ASCII);
  • \n — символ перевода строки newline (hex OA в ASCII);
  • \г — символ возврата каретки (hex OD в ASCII);
  • \t — символ табуляции (hex 09 в ASCII);
  • \сх — символ «Control-X», где х — любой буквенный символ.

Фактическое же действие последовательности \сх следующее: если «х» в нижнем регистре, он преобразуется в верхний, затем бит 6 (hex 40) этого символа инвертируется. Таким образом «\cz» становится шестнадцагеричным 1А, а «\с{»становится \хЗВ, тогда как «\с;» становится \х7В.

2. Подстановка символа с указанным кодом.

Для подстановок этого вида используются две записи:

  • \хшш, где шш — одна или две шестнадцатиричных цифры, буквы можно указывать в верхнем или нижнем регистре;
  • \ДДД, где ДДД — одна-три восьмеричных цифры.

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

3. Подстановка фрагмента совпадения с подшаблоном (обратная ссылка).

Указываются в виде: \ДД, где ДД — одна-две десятичных цифры (1-99) без незначащих нулей. Таким образом, обратных ссылок не может быть более 99. См. подробную информацию в разделе «Подшаблоны».

4. Подстановка класса символов.

  • \d — любой цифровой символ, [0-9];
  • \0 — любой НЕцифровой символ, [*0-9];
  • \s — любой пробельный символ, [\t\ \r\f\n];
  • \S — любой НЕпробелышй символ;
  • \w — любой алфавитно-цифровой символ;
  • \W — любой НЕалфавитно-цифровой символ.

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

Эти подстановки можно включать в класс символов.

5. Обозначение общего вида претензий.

  • \b — «на границе слова»;
  • \В — «не на границе слова»;
  • \А — в начале текста;
  • \Z — в конце текста или перед символом перевода строки;
  • \z — в конце текста.

Последовательности \А, \Z и \z, в отличие от метасимволов $ и А, действуют вне зависимости от режима многострочности (см. модификатор т).

Эти последовательности не должны использоваться в классах символов.

См. также раздел «Претензии».

Если после слеша указывается буква и эта последовательность не имеет специального значения подстановки, обычно слеш игнорируется и последовательность воспринимается как обычная буква. При установке же модификатора X такая последовательность вызывает ошибку. Это сделано для того, чтобы в дальнейшем, если когда-то такая последовательность приобретет специальное значение, она не использовалась бы неумышленно.

Альтернативы и классы символов

Допустим, в тексте нужно найти слово: «АА», «Бб» или «ВвВ», тогда в шаблоне следует указать 'АА|Бб|ВвВ', используя как обозначение альтернативы знак |, Допустимо любое число альтернатив и пустая альтернатива (соответствующая пустому фрагменту). Перебор альтернатив производится слева направо, и используется первая подходящая.

Для удобства можно заключать список альтернатив в скобки (то есть образовывать, таким образом, подшаблон), и в дальнейшем ссылать-ся на найденную альтернативу с помощью обратной ссылки. Например, шаблон: '*<(Н1|Н2|НЗ)>( .*)</\\l>*imUs' будет искать содержимое тегов заголовков.

Иногда необходимо искать символ, который может принимать различные значения, тогда используется класс символов, обозначаемый символами «[» и «]». Чтобы использовать символ ] в классе символов в качестве «самого себя», следует ставить перед ним слеш: \].

Если первый символ класса «А», то это означает: «любой символ, кроме тех, которые указаны в классе». Символ минус обозначает (если он не является первым или последним символом класса) символьный диапазон. Например, класс [лО-9] соответствует любому нецифровому символу (также можно записать как [А\хЗО-\х39]). Любую английскую букву можно указать как [a-z] |[A-Z]'. Если необходимо включить в класс символы «А» и «-», то первый не должен быть первым символом класса, а второй должен стоять в начале или конце класса.

В классе символов или вместо них допускается использование подстановок: \d, \D, \s, \S, \w. \W. Например, можно использовать последовательность \D вместо [лО-9]; или [\da-fA-F] для указания «любой шсстнадцатеричной цифры».

Класс символов в отличие от альтернатив сопоставляется только одному символу! Для того чтобы найти несколько символов из класса, используйте числители.

Прочие метасимволы (например, «$» или «}») в классе метасимволами не являются, но все же их желательно предварять слешем.

Особое значение имеет метасимвол «точка» (вне класса символов). Фактически он эквивалентен классу [*/n], представляющему собой совпадение с любым символом (включая также непечатные). Но, по умолчанию, если не используется модификатор s, ему не может соответствовать символ перехода на новую строку (\n); при указании же модификатора s точка соответствует абсолютно любому символу (то есть классу [\0-\xFF]).

Повторения и числители

Предположим, вы хотите найти в тексте номер, состоящий из 3-5 десятичных цифр, тогда в шаблоне необходимо указать \d{3,5}. Как вы можете догадаться, повторения символа (или, возможно, подшаб-лона) обозначаются указанием после него чисел в фигурных скобках, где первое число — минимально допустимое повторение символа (подшаблона), а после запятой — максимальное. Числители могут представляться также в следующем виде:

  • {n} — повторение, указанное n число раз;
  • {n,} — повторение, не меньше чем n раз.

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

Заменитель числителя Значение Эквивалент
у « 1 или 0 раз» {0,1}
* «0 или более раз» {0,}
+ «1 или более раз» 1.}

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

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

<Р> Текст <Р> абзаца</Р> со вложениями </Р>

Тогда шаблон /<p>(.*)<\/p>/i может (теоретически) вернуть 4 варианта совпадения. По умолчанию ищется максимальное повторение (то есть в данном варианте — строка целиком). Чтобы находилось минимально повторяющееся значение, используйте модификатор U. Для снижения «жадности» не всех числителей а только избранных ставьте после них знак вопроса, например: /<p>(.*?)<\/p>/i; этот способ изменяет «жадность» числителя на противоположную от основной.

Числитель может указываться не только после символа, класса, под-шаблона, но и после обратной ссылки.

Подшаблоны и обратные ссылки

Сами по себе подшаблоны (части шаблона, заключенные в круглые скобки) не влияют на функционирование регулярных выражений и могут служить исключительно для удобства группировки (они могут быть вложенными). Подшаблон может использоваться для ограничения набора альтернатив. При использовании же с обратными ссылками подшаблоны являются действенным инструментом поиска. Например, для поиска содержимого парных тегов может использоваться запись: *<([*>]*)>(.*)</\\1>*.

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

Заметьте, вместо ссылки подставляется фрагмент реального текста; например, регулярное выражение /слов(о|а) и числ\1/ будет подходить фразе: «слово и число» и «слова и числа», но не «слова и число»; а регулярное выражение /(A+)6\l/i не будет подходить строке «Аба», хотя и указано игнорирование регистра.

Ссылка может быть использована тогла и в том месте шаблона, когда ей уже можно будет однозначно сопоставить фрагмент текста. Например, конструкции (а\1) и (а|(b+))\2 неправильны.

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

(.*), (.)*, ([abc]*), ([abc])* (\2|\1+), (\2|\1)+.

Когда на подшаблон не имеется ссылок, его можно пометить указанием после открывающей скобки последовательности ?:, это исключает подшаблон из списка ссылок. Например, регулярное выражение /a((b+)(?:c*))(d?)/ будет иметь три ссылки: 1 -- на подшаблон ((b+)(?:с*)), 2 — на (b+) и 3 —.на (d?). Это может использоваться для увеличения общего числа подшаблонов до 200 (99 со ссылками и 101 без них). В такой форме записи становится возможным указывать внутренние модификаторы между ? и :, например: (?i:c|e|) эквивалентно (?:(?i)c|e|).

При необходимости указания внутри шаблона комментария (и возможном нежелании использовать модификатор х) допустимо исполь-

зовать подшаблоны комментариев (?#мой комментарий), игнорируемые при обработке.

Претензии

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

Простейшие из них " и $ обозначают, что фрагмент должен находиться соответственно в начале или в конце текста. Так, шаблон /*А/ указывает на то, что ищется символ «А» в начале текста, а шаблон /Z$/ на то, что ищется символ «Z» в конце текста. Как видно из примеров, сами символы л и $, должны находиться соответственно в начале или конце шаблона. Шаблон /привет$/ будет проверять, состоит ли текст целиком из слова «привет».

У этих претензий есть одна особенность: что считать началом и концом текста (строки)? Установка модификатора m указывает на то, что конец и начало строки могут обозначаться символом (\п). Например, шаблон /~А/т ищет букву «А» либо в начале текста, либо после каждого символа (\п). При установленном модификаторе D знак $ обозначает исключительно фактический конец текста, иначе же (если указан модификатор т) он также может обозначать конец строки, то есть то, что непосредственно после фрагмента должен следовать символ перевода строки (\п). В отличие от модификатора D, влияющего только на претензию конца строки, модификатор m влияет на обе. Если текст не содержит символов перевода строки, эти модификаторы не имеют значения.

Следующими претензиями, аналогичными описанным выше, являются подстановки \А, \Z, \z, обозначающие соответственно фактическое начало текста, конец текста или перевод строки, и фактический конец текста. Эти претензии не зависят от модификаторов. Например, шаблон /\A.*T\Z.+\z/ra будет искать символ «Т» в конце строки, но не текста.

Дополнительными похожими претензиями являются подстановки \b и \В, обозначающие соответственно «на» и «не на» границе «слова». Словом считается последовательность, ограниченная пробельными символами (включая переводы строк) или началом или концом текста. А границей — промежуток между двумя символами, один из которых пробельный, а другой нет. Например, шаблон /\bпре(\^)ый\b/ ищет все слова, имеющие приставку «пре-» и окончание «-ый».

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

  • (?=текст) — текст после точки совпадения должен соответствовать указанному;
  • (?!текст) — текст после точки совпадения не должен соответствовать указанному;
  • (?<=текст) — текст до точки совпадения должен соответствовать указанному;
  • (?<!текст) — текст до точки совпадения не должен соответствовать указанному.

Их отличие от простого указания последовательностей в подшабло-не в том, что фрагмент совпадения с такой претензией не возвращается в результате. Например, шаблон /(?<=\()\w+(?=\))/ возвращает всякое слово, стоящее в скобках без пробелов, но сами скобки не возвращаются.

В претензиях возможно указывать альтернативы и все то, что может использоваться в обычных шаблонах, кроме повторений. Для претензий предшествия альтернативы не должны иметь неопределенную длину, например, следующая претензия допустима: (?<lа[bс), в то время как недопустимы: (?<!а(а be)) и (?<lа?|bс).

Допустимо использовать последовательности претензий, например (?<=\d{3}) (?<!000)\w соответствует слову, которому предшествуют три цифры, не являющиеся одновременно нулями. Таким образом, можно производить многочисленные проверки одного места совпадения.

Также возможны вложения, например (?<=(?<!вв)ББ)аа будет соответствовать фрагменту «ББаа», но не «ввББаа». На подшаблоны претензий ссылки не указываются.

Специальные структуры подшаблонов

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

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

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

Допустим, необходимо определить, оканчивается ли длинный текст на символы «Хх». При обычном шаблоне /Хх$/ проверка будет проходить от начала текста (сначала будет искаться символ, а потом определяться, стоит ли он в конце). Если усложнить шаблон до Г(. .*)Хх$/, это не сильно ускорит обработку, так как большую часть времени будет перебираться повторение первого подшаблона, и только потом определяться окончание текста. Если же написать шаблон как: /А(?>.*)(?<=Хх}$/, то первый подшаблон сразу же захватит весь текст целиком, а затем будет проверено окончание.

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

(? (условие) подшаблон!) или (?(условие)подшаблон1|подшаблон2).

При выполнении условия используется первый подшаблон, в противном случае (если он указан) — второй. Условия бывают двух типов.

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

/ ( ( \( )? # необязательная открывающая скобка ( [*()]+ ) # все. кроме скобок С?(2) \) )# если была открывающая скобка, должна быть закрывающая )+ I повторим? /х

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

/ (?(?=х) # если префикс х [\da-fA-F]+ # то шестнадцатеричное число Синтаксис регулярных выражений (PCRE) I \d+ # иначе - десятичное ) /x

Модификаторы

Функционирование регулярных выражений можно видоизменять модификаторами трех уровней: глобальными, внешними и внутренними.

Модификатор Внутреннее имя Воздействие
i PCRE_CASELESS Игнорировать регистр
S PCRE_DOTALL Точка = [\0-\xFF], а не [А\п]
и PCRE_UNGREEDY Минимизировать числитель
га PCRE_MULTILINE А, $ учитывают \п
D PCRE_DOLLAR_ENDONLY $ не учитывает \п
А PCRE_ ANCHORED Привязать шаблон к началу текста
е Только для preg_rep!ace()
X PCRE_EXTENDED Разрешить комментарии: пробел и #
X PCRE_EXTRA Воспринимать неверную подстановку как ошибку
S   Предварительная оптимизация шаблона перед исполнением

Значение модификаторов и их использование описаны в соответствующих разделах.

Модификатор га обладает большим приоритетом, чем 0. Модификатор А предназначен для ускорения обработки, но более выгодно явное конструирование оптимизированных шаблонов, например /.*шаблон/з для однострочного текста.

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

Модификаторы i, m, s, x, U, X можно устанавливать внутри шаблона, внутри подшаблона модификаторов (? ... ), после знака вопроса. Если в таком подшаблоне присутствует знак «минус», то модификаторы, стоящие за ним, сбрасываются. Действие таких модификаторов распространяется на промежуток шаблона от места его указания до его следующего возможного указания (со знаком минус) или до конца шаблона. Например: /аб(?51)вгде(?х-1т)ж(?тт: .*)з/га. При указании внутренних модификаторов внутри подшаблона их действие (в отличие от Perl) распространяется только на этот подшаблон. Например, шаблон /(а(?1)б)в/ соответствует только фрагментам «абв» и «аБв», а шаблон /(а(?1)б|г)/ соответствует фрагментам: «аб», «аБ», «г» или «Г».



Содержание раздела