ProfiPHPProfiPHP
Категория: PHP для чайников

Регулярные выражения в PHP

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

Существует несколько разных диалектов регулярных выражений, среди которых один из самых распространенных и развитых является синтаксис Perl-совместимых регулярных выражений (PCRE - Perl Compatible Regular Expressions).

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

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

Допустимо использовать инструкции модификаторы шаблона, которые действующие на все регулярное выражение. Например, модификатор "i" будет осуществлять поиск по регулярному выражению без учета регистра. Для русских символов в кодировке UTF8, для правильной обработки необходимо добавлять модификатор "u" (PCRE_UTF8). Например:
"/комп/ui"
Регулярное выражение из примера будет соответствовать как строке "компьютер", так и "КОМПЬЮТЕР".

Для привязки регулярного выражения к началу слова используется символ "^" (caret - знак вставки):
"/^свет/"
Данное выражение будет соответствовать строке "светильник", и не будет соответствовать слову "рассвет".

Знак доллара "$" означает конец строки:
"/^светильник$/"
Данное регулярное выражение соответствует исключительно строке "светильник", где после искомого слова нет другого текста.

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

В качестве разделителя может выступать любой другой символ, например "|":
"|^светильник\/потолочный$|ui"
Изменять разделители необходимо выходя из задачи поиска, например, если символ косой черты "/" встречается часто в поисковой строке, то его можно изменить.

Следует быть очень внимательными используя некоторые символы для разделителей, поскольку они могут выполнять свою роль в шаблоне. Использование символа вертикальной черты "|" в регулярном выражении может быть использовано для задания альтернативных масок:
"/^abc|def$/"
Данному регулярному выражению соответствует любая строка, содержащая подстроки "abc" или "def". Вертикальную черту в большинстве случаев применяют при проверке, например, расширений файлов или зон доменных имен.

Подстроки в регулярных выражениях можно группировать при помощи скобок "()":
"/^цвет (красный|синий|зеленый)$/"
Это регулярное выражение будет соответствовать строке вида "цвет красный", но вместо "красный" может быть как "синий", так и "зеленый".

Для использования скобок как части искомой строки, их следует экранировать. Например, соответствовать строке "цвет (красный)" будет следующее регулярное выражение:
"/^цвет \(красный\)$/"
Кроме группировки символов, скобки имеют еще одно предназначение. Все выражения, найденные в скобках, сохраняются интерпретатором, и к ним можно обратиться при замене или поиске по номеру скобки.

Чтобы задать класс символов необходимо использовать квадратные скобки "[]". Они ограничивают поиск теми символами, которые в них заключены:
"/[abc]/"
Данному регулярному выражению будет соответствовать подстрока, которая содержит хотя бы один символ из "abc".

Для создания регулярного выражения, которое соответствует всем буквам английского алфавита, можно перечислить все буквы в регулярном выражении, а можно записать более коротко следующим образом:
"/[a-z]/i"
Любые два символа, разделяемые дефисом, задают соответствие диапазону символов, находящихся между ними. В данном регулярном выражении описаны символы нижнего регистра, но модификатор "i" осуществляет регистрозависимый поиск.

Аналогичным образом задаются регулярные выражения, соответствующие цифре:
"/[0-9]/"
При использовании экранирования обратным слешем некоторые символы выполняют специальную интерпретацию:

\d - любая десятичная цифра ([0-9]);

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

\s - любой пробельный символ ([ \r\n\t\f]);

\S - любой непробельный символ;

\w - любой символ, образующий "слово" ([a-zA-Z0-9_]);

\W - любой символ, не образующий "слово";

\t - символ табуляции;

\n - символ перевода строки;

\\ - символ обратного слеша (\);

\. - символ точки (.).

Символ точки "." обозначает любой символ в регулярном выражении кроме символов разрыва строки "\r" или "\n", поэтому для поиска точки следует экранировать этот символ.

Регулярное выражение для числа можно записать следующим образом:
"/[\d]/"
Чтобы исключить класс символов из поиска необходимо в квадратных скобках поставить первым символ "^", который действует уже не как указатель границы строки, а как отрицание:
"/[^0-9]/"
Данное регулярное выражение отвечает любому символу, не содержащемуся в диапазоне "0-9".

Список специальных символов (метасимволы):
\^$.[]|()?*+{}
Выражение в квадратных скобках часто применяется совместно с так называемыми квантификаторами, которые являют собой символы "?", "+" и "*". Квантификаторы следуют сразу за символом и изменяют число вхождений конкретного символа в строку:

? - символ либо входит в строку один раз, либо вообще в нее не входит;

* - любое число вхождений символа в строку, в том числе и 0;

+ - одно или более число вхождений символа в строку.

Например, если необходимо найти подстроку, содержащую одну или более цифр, следует воспользоваться выражением вида:
"/[\d]+/"
Символ "*" используется для любого числа вхождений строки в подстроку, то есть слудеющее регулярное выражение соответствует либо пустой строке, либо строке, содержащей неограниченное количество цифр.
"/^[\d]*$/"
В регулярных выражениях так же применяются фигурные скобки ({}), которые предназначены для указания числа или диапазона чисел повторения элемента:

"ab{2}" - соответствует строке "abb";

"ab{2,}" - соответствует строке, в которой за "b" следует не менее двух "b";

"ab{2,4}" - соответствует строке, в которой за "b" следует от 2 до 4 символов "b".

Выражение "{0,}" полностью аналогично "*", а "{1,}" - "+". Выражение "{0,1}" можно записать более коротко, используя "?".

Для объединения символов в последовательность, их необходимо поместить в круглые скобки. Например, следующее регулярное выражение соответствует строке, в которой за "a" следует от 2 до 4 последовательностей "bc";
"a(bc){2,4}/"
Функции для работы с регулярными выражениями

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

Первой рассмотрим функцию Preg_match, которая осуществляет поиск в строке по регулярному выражению и имеет следующий синтаксис:
int preg_match( string $pattern, string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
Функция Preg_match ищет в заданном тексте Subject совпадения с шаблоном Pattern. Если задан необязательный параметр Matches, то результаты поиска помещаются в массив. Элемент $matches[0] будет содержать часть строки, соответствующую вхождению всего шаблона, $matches[i] - часть строки, соответствующей первым круглым скобкам, $matches[2] - вторым и т. д.

Необязательный параметр Flags может принимать единственное значение PREG_OFFSET_CAPTURE, при указании которого изменяется формат возвращаемого массива $matches - каждое вхождение возвращается в виде массива, в нулевом элементе которого содержится найденная подстрока, а в первом - смещение. Поиск осуществляется слева направо, с начала строки.

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

Для поиска всех совпадений, следует воспользоваться функцией Preg_match_all, которая имеет следующий синтаксис:
int preg_match_all( string $pattern, string $subject [, array &$matches [, int $flags = PREG_PATTERN_ORDER [, int $offset = 0 ]]] )
Функция Preg_match_all ищет в строке Subject все совпадения с шаблоном Pattern и помещает результат в массив Matches в порядке, определяемом комбинацией флагов Flags. Так же как и в предыдущей функцией можно задать смещение Offset, начиная с которого будет осуществляться поиск встроке Subject. После нахождения первого соответствия последующие поиски будут осуществляться не с начала строки, а от конца последнего найденного вхождения.

Перейдем к функции, которая кроме поиска осуществляет и замену по регулярному выражению — Preg_replace:
mixed preg_replace( mixed $pattern, mixed $replacement, mixed $subject [, int $limit = -1 [, int &$count ]] )
Функция Preg_replace выполняет поиск совпадений в строке Subject с шаблоном Pattern и заменяет их на Replacement.

Функция Preg_split разбивает строку по регулярному выражению.
array preg_split( string $pattern, string $subject [, int $limit = -1 [, int $flags = 0 ]] )
Функция возвращает массив, состоящий из подстрок заданной строки Subject, которая разбита по границам, соответствующим шаблону Pattern.

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

Также существуют дополнительные конструкции шаблонов:

(?#комментарий) - комментарий в теле шаблона. Иногда очень полезно разместить в теле регулярного выражения конкретный комментарий для лучшего понимания работы.

(?:шаблон) - группировка как и "( )", но без обратной ссылки. Данная группировка очень полезна для задания шаблона но без создания обратной ссылки.

(?=шаблон) - "заглядывание" вперед. Данная конструкция может понадобится для поиска по шаблону с наперед указанным выражением, например, выражение "/\w+(?=\t)/" соответствует слову, за которым идет символ табуляции, но символ "\t" не включается в результат.

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

Проверка правильности ввода E-mail:
preg_match( "/^[a-z0-9_\-\.]+@[a-z0-9_^\.]+\.[a-z]{1,6}$/ui", $email )
До символа собачки шаблон ищет буквы и цыфры, знак тире, нижнего подчеркивания и
крапки одно или более число вхождений начиная от начала строки:
^[a-z0-9_\-\.]+
Далее следует вторая часть почтового адреса, начиная с собачки имея тот же набор символов, что и первая часть:
@[a-z0-9_^\.]+
После этого проверяем доменную зону, которая состоит исключительно из строки букв определенного количества символов до конца строки:
\.[a-z]{1,6}$
Также с помощью регулярного выражения мы может выбрать все E-mail из текста:
$text = 'Здесь текст и почтовый адрес test@gmail.com а также еще один адрес admin@mail.ru';
preg_match_all( "/[a-z0-9_\-\.]+@[a-z0-9_^\.]+\.[a-z]{1,6}/ui", $text, $matches, PREG_PATTERN_ORDER );
foreach ( $matches[0] as $key => $val ) {
$email = filter_var( $val, FILTER_VALIDATE_EMAIL );
if ( $email ) $output[ ] = $email;
}
В отличии от проверка правильности ввода E-mail, при выборке мы убрали в шаблоне символ начала (^) и конца ($) строки. Результат данного примера:
Array
(
[0] => test@gmail.com
[1] => admin@mail.ru
)
Проверка правильности ввода имени:
preg_match( '#^[а-яґїієa-z\-\_\'.\d\s]+$#ui', $name );
Проверка правильности ввода числа:
preg_match( '/([0-9]+)/ui', $id )
Корректность ввода даты:
$date = "2017.05.25";
preg_match( '/^[0-9]{4}.[0-9]{2}.[0-9]{2}$/ui', $date );
Удалить все определения стилей Style:
preg_replace( '/style=\"[^\"]*\"/', '', $string );
Поскольку стили могут находится внутри практически любого тега, в примере удаляется исключительно само определение стиля без тега.

Удалить все определения строчных элементов документа Span:
preg_replace( '#<span[^>]*?>#is', '', $string );
preg_replace( '#<\/span>#is', '', $table );
Точно так же можно удалить любой тег, например, для заголовка H1:
preg_replace( '#<h1[^>]*?>#is', '', $table );
preg_replace( '#<\/h1>#is', '', $table );
Очистку таблиц с помощью регулярных выражений PHP можно осуществить так:
// Удаляем все из атрибутов Table:
$table = preg_replace( '#<table.*>#siU', '<table>', $table );
// Удаляем все из атрибутов TR:
$table = preg_replace( '#<tr.*>#siU', '<tr>', $table );
// Удаляем все из атрибутов TD (кроме colspan или rowspan):
$table = preg_replace( '#<td[^>]+((colspan|rowspan)=[^\s>]+?)(|.*)>#siU', '<td \\1>', $table );
Проверить правильность имени файла можно с помощью следующего регулярного выражения:
preg_match( "/(^[a-zA-Z0-9]+([a-zA-Z\_0-9\.-]*))$/", $filename )

Комментарии

Андрей
Спасибо за доступную и легкую для восприятия информацию.

Добавить комментарий

Имя:
Текст комментария: