Главное меню

Введение в регулярные выражения

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

Регулярные выражения POSIX (Portable Operating System Interface for computer environments – интерфейс переносимой операционной системы) легче освоить, однако они не являются безопасными к бинарным данным.

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

Основы

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

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

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

Наборы символов и классы

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

Прежде всего, символ "." можно применять в качестве группового символа для любого другого одиночного символа, за исключением символа новой строки (\n). Например, регулярное выражение:

. ом

соответствует, в частности, строкам 'дом', 'ком' и 'лом'.

Этот вид сопоставления групповых символов часто применяется для сопоставления имен файлов в операционных системах.

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

[a-я]ом

Все, что заключено в квадратные скобки [ и ], представляет класс символов, т.е. набор символов, к которому должен принадлежать сопоставляемый символ. Обратите внимание, что заключенное в квадратные скобки выражение сопоставляется только с одиночным символом.

Набор можно указать в виде списка. Например:

[аеиоуыэюя]

означает любую гласную.

С помощью символа дефиса можно задавать не только диапазон, как это только что было сделано, но и набор диапазонов:

[a-zA-Z]

Этот набор диапазонов означает любую строчную или прописную букву английского алфавита.

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

[^а-z]

соответствует любому символу, не содержащемуся в диапазоне a-z. Когда символ вставки ^ помещен внутрь квадратных скобок, он означает "не". При использовании вне квадратных скобок он имеет другое значение, о чем речь пойдет несколько позже.

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

Введение в регулярные выражения

Повторение

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

[[:alnum:]]+

означает "по меньшей мере один алфавитно-цифровой символ".

Подвыражения

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

(очень )*крутой

соответствует строкам 'крутой', 'очень крутой', 'очень очень крутой' и т.д.

Подвыражения с подсчетом

Количество повторений какой-либо строки можно указать с помощью числового выражения, заключенного в фигурные скобки ({}). При этом можно задавать точное число повторений ({3} означает в точности 3 повторения), диапазон повторений ({2, 4} означает от 2 до 4 повторений) или указывать открытый диапазон повторений ({2, } означает не менее двух повторений).

Например:

(очень ){1, 3}

соответствует строкам 'очень', 'очень очень' и 'очень очень очень'.

Привязка к началу или концу строки

Шаблон [a-z] будет соответствовать любой строке, содержащей строчную букву английского алфавита. При этом неважно, имеет ли строка длину в один символ, либо совпадение произошло с одним символом в длинной строке.

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

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

Например, наличию подстроки вован в начале просматриваемой строки соответствует следующее выражение:

^вован

Наличию подстроки com в конце просматриваемой строки соответствует такое выражение:

com$

И, наконец, любому одиночному символу от а до z, расположенному в отдельной строке, соответствует приведенное ниже выражение:

^[a-z]$

Ветвление

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

com|edu|net

Сопоставление с литеральными значениями специальных символов

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

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

Аналогично, если требуется указать обратную косую черту в РНР-строке в двойных кавычках, косых черт также должно быть две, по тем же самым причинам. Тот факт, что в результате применения этих правил РНР-строка, представляющая регулярное выражение с литеральной обратной косой чертой, должна содержать четыре косых черты, многих сбивает с толку. Интерпретатор РНР преобразует четыре косых черты в две, а затем интерпретатор регулярных выражений преобразует две косых черты в одну.

Знак доллара ($) также является специальным символом в РНР-строках в двойных кавычках и в регулярных выражениях. Чтобы представить литеральный символ $ в шаблоне, потребуется указать "\\\$". Поскольку строка находится в двойных кавычках, интерпретатор РНР преобразует ее в \$, после чего интерпретатор регулярных выражений будет трактовать ее как символ $.

Краткое описание специальных символов

Краткое описание всех специальных символов приведено в табл. 4.4 и 4.5. В табл. 4.4 перечислены значения специальных символов, когда они не заключены в квадратные скобки, а в табл. 4.5 – значения, которые они приобретают, находясь внутри квадратных скобок.

Введение в регулярные выражения

Введение в регулярные выражения

Использование регулярных выражений в приложении отправки электронной почты

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

магазин|доставк|розничн

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

^[a-zA-Z0-9_\-.]+@[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-\.]+$

Подвыражение ^[a-zA-Z0-9_\-.]+ означает "в начале строки находится, по меньшей мере, одна буква, цифра, символ подчеркивания, дефис, точка или какое-либо их сочетание".

Символ @ соответствует литералу @.

Подвыражение [a-zA-Z0-9\-]+ соответствует первой части имени хоста, которое включает алфавитно-цифровые символы и дефисы. Обратите внимание на то, что перед символом дефиса поставлена косая черта, поскольку внутри квадратных скобок он представляет собой специальный символ.

Комбинация \. соответствует точке (.). Поскольку символ точки используется вне класса символов, она должна быть литерализована, дабы соответствовать литеральной точке.

Подвыражение [a-zA-Z0-9\-\.]+$ соответствует оставшейся части имени домена, включающей буквы, цифры, дефисы и дополнительные точки, если они требуются, вплоть до конца строки.

Несложный анализ показывает, что можно ввести недопустимые адреса электронной почты, которые, тем не менее, будут соответствовать этому регулярному выражению. Практически невозможно отловить все такие адреса, но все-таки данное регулярное выражение позволит хоть немного улучшить ситуацию. Вы можете усовершенствовать это выражение многими способами. Например, можно воспользоваться списком действительных доменов верхнего уровня (top-level domain – TLD). Однако соблюдайте осторожность при установке различных ограничений, поскольку проверочная функция, отвергающая хотя бы 1% допустимых данных, вызывает большее раздражение, чем аналогичная функция, пропускающая 10% недопустимых данных.

Теперь, когда вы познакомились с регулярными выражениями, перейдем к рассмотрению РНР-функций, которые используют эти выражения.

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

Поиск подстрок – это основное применение только что рассмотренных регулярных выражений. В РНР существуют две функции, предназначенные для сопоставления с регулярными выражениями: ereg() и eregi().

Функция ereg() ("regular expression" – "регулярное выражение") имеет следующий прототип:

int ereg(string pattern, string search [, array matches]);

Эта функция выполняет поиск в строке search, отыскивая в ней соответствия регулярному выражению, которое определено в шаблоне pattern. Если соответствия подвыражений с шаблоном pattern будут найдены, они сохраняются в массиве matches, по одному подвыражению в каждом элементе массива.

Функция eregi() идентична предыдущей, за исключением того, что она не чувствительна к регистру.

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

if (!eregi('^[a-zA-Z0-9_\-.]+@[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-.]+$', $email)) {

echo "<р>Неверен адрес электронной почты.</р>" .

"<р>Вернитесь на предыдущую страницу и попробуйте еще раз.</р>";

exit;

}

$toaddress = "feedback@example. com"; // значение по умолчанию

if (eregi("магазин|доставк|розничн", $feedback)) {

$toaddress = "retail@example. com";

} else if (eregi("доставк|обязательств", $feedback)) {

$toaddress = "fulfillment@example. com";

} else if (eregi("счет|рассчит", $feedback)) {

$toaddress = "accounts@example. com";

}

if (eregi('bigcustomer\.com', $email)) {

$toaddress = 'bob@example. com';

}

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

Регулярные выражения можно применять для поиска и замены подстрок так же, как это делалось с помощью функции str_replace(). Для решения этой задачи предназначены две функции: ereg_replace() и eregi_replace().

Функция ereg_replace() имеет следующий прототип:

string ereg_replace(string pattern, string replacement, string search);

Эта функция ищет регулярное выражение pattern в строке search и заменяет его строкой replacement.

Функция eregi_replace() совпадает с ней, за исключением того, что она не чувствительна к регистру.

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

Еще одна полезная функция обработки регулярных выражений, split(), имеет следующий прототип:

array split(string pattern, string search [, int max]);

Эта функция разбивает строку search на подстроки в соответствии с регулярным выражением pattern и возвращает подстроки в массиве. Целочисленный параметр max ограничивает количество подстрок, которые могут быть помещены в массив.

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

$address = "username@example. com";

$arr = split ("\.|@", $address);

while (list($key, $value) = each ($arr) ) {

echo "<br />".$value;

}

Этот фрагмент кода делит адрес электронной почты на пять компонентов и выводит каждый из них в отдельной строке:

username

@

example

.

com

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