Разработчику. Сборник рецептов PHP
Задавайте вопросы

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

Вернуться назад

Введение

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

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

$html = preg_replace('/[^@\s]+@([ -a-z0-9]+\.)+[a-z]{2,}/i',
                                          '<a href="mailto:$0">$0</a>', $text);

Как видите, регулярные выражения довольно удобны для преобразования простого текста в форматHTML и наоборот. К счастью, эта тема столь популярна, что в PHP уже имеется множество встроенных функций для решения таких задач. В рецепте-(Пользовательские данные и escape-последовательности) рассказано, как превращать сущности HTML в escape-последовательности, рецепт-(Удаление тегов HTML и PHP). посвящен удалению тегов HTML, а в рецептах (Преобразование ASCII в HTML) и (Преобразование HTML в ASCII) показано, как конвертировать ASCII в HTML и, соответственно, HTML в ASCII. Дополнительные сведения о поиске и проверке адресов электронной почты посредством регулярных выражений можно почерпнуть из рецепта-(Поиск в файле всех строк, соответствующих шаблону).

За несколько лет функциональное назначение регулярных выражений сильно расширилось по сравнению с их базовыми возможностями и теперь включает в себя множество чрезвычайно полезных характеристик. В результате PHP в современном виде предлагает два различных набора функций для работы с регулярными выражениями. Первый набор включает традиционные (или POSIX) функции, которые начинаются с префикса ereg (от «extended regular expressions» – расширенные регулярные выражения; фактически функции ereg уже сами по себе являются расширением базового набора возможностей). Другой набор включает в себя функции Perl-диалекта регулярных выражений с префиксом preg (от «Perlcompatible regular expressions»–Perl-совместимые регулярные выражения).

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

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

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

if (preg_match('/<img /', $html)) {
                        // найден открывающий тег изображения
}

Функция preg_match() сравнивает шаблон <"img " с содержимым переменной $html. Если она находит совпадение, то возвращает значение 1;в противном случае возвращается 0. Символы / называются разделителями шаблона; они определяют начало и конец шаблона.

Есть и несколько специальных символов. Причем именно их специальная природа расширяет возможности регулярных выражений по сравнению с такими функциями, как strstr() и strpos().Такие символы называют метасимволами. К наиболее часто используемым метасимволам относятся точка (.), звездочка (*)>, плюс (+) и знак вопроса (?). Соответственно, чтобы задать в шаблоне поиск символа, соответствующего метасимволу, необходимо поставить перед символом обратную косую черту (\).

• Точка соответствует любому символу, поэтому шаблон /.at/ будет совпадать с bat, cat и даже с rat.

• Звездочка означает 0 или более повторений предшествующих объектов. (В настоящий момент единственными объектами, о которых нам известно, являются символы.)

• Действие плюса подобно действию звездочки, но означает 1 или более повторений, а не 0 или более. Поэтому /.+at/ соответствует brat, sprat и даже catastrophe, но не at. Чтобы найти at, нужно заменить + на *.

• Знак вопроса означает 0 или 1 объект.

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

if (preg_match('/<title>.+<\/title>/', $html)) {
              // страница имеет название

}

if (preg_match_all('/<li>/', $html, $matches)) {
              print 'Page has ' . count($matches[0]) . " list items\n";

}

// превращаем полужирный шрифт в курсив
$italics = preg_replace('/(<\/?)b(>)/', '$1i$2', $bold);

Если вы хотите найти строки, состоящие из определенного набора букв, создайте символьный класс из этих букв. Символьный класс представляет собой последовательность символов, заключенную в квадратные скобки. Знак вставки (^) и знак доллара ($) связывают шаблон с началом и концом строки соответственно. Без их указания поиск совпадений может происходить в любом месте строки. Поэтому, для того чтобы найти все гласные в строке, надо создать символьный класс, содержащий a, e, i, o и u, начать шаблон с символа ^ и закончить его символом $:

preg_match('/^[aeiou]+$/', $string); // только гласные

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

preg_match('/^[^aeiou]+$/', $string) // только не гласные

Обратите внимание, противоположность [aeiou] – это не только [bcdfghjklmnpqrstvwxyz]. Символьный класс [^aeiou] также соответствует гласным в верхнем регистре, таким как AEIOU, числам, например 123, URL, таким как http://www.cnpq.br/, и даже смайликам, например :).

Вертикальная черта (|), используемая также для указания канала, задает указание альтернативы, например:

// находим gif или jpeg
preg_match('/(gif|jpeg)/', $images);

Кроме рассмотренных выше, существует еще одна группа метасимволов. Они действуют схожим образом, но соответствуют не одному, а нескольким символам. Полезными метасимволами из этой группы являются: \w (соответствует любому текстовому символу, [a-zA-Z0-9_]);(*) \d(соответствует любой цифре, [0 9]); \s (соответствует любому пробельному символу) и \b (соответствует границе слова).(**) Ниже показано,как найти все числа, которые не являются частью другого слова:

// находим цифры, не соприкасающиеся с другими словами
preg_match_all('/\b\d+\b/', $html, $matches);

Это соответствует 123, 76! и 38-years-old, но не 2nd.

Приведем шаблон, представляющий собой регулярное выражение, эквивалентное функции trim():

// удаляем начальные или заключительные пробельные символы
$trimmed = preg_replace('/(^\s+)|(\s+$)/', '', $string);

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

// точное совпадение только с тегами изображения
// в нижнем регистре (допускается в XHTML)
if (preg_match('/<img[^>]+>/', $html)) {

          ...

}

// соответствует тегам изображения и в верхнем, и в нижнем регистре
if (preg_match('/<img[^>]+>/i', $html)) {

           ...

}

Мы затронули лишь небольшое подмножество регулярных выражений. Некоторые дополнительные аспекты мы рассмотрим в следующих рецептах, а на веб-сайте PHP, по адресу http://www.php.net/regex можно найти очень полезную информацию о регулярных выражениях POSIX, тогда как регулярные выражения, поддерживающие диалект Perl, рассмотрены по адресу http://www.php.net/pcre. На этой последней странице приведены также ссылки на очень подробные и информативные разделы «Pattern Modifiers» (Модификаторы шаблонов) и «Pattern Syntax» (Синтаксис шаблонов).


(*)   В оригинале – «any word character», что можно перевести как «любой текстовый символ». Данная нотация заимствована из языка Perl. Фактически множество символов \w трактуется в нем как множество символов, допустимых в идентификаторах (именах переменных). Это изначально соответствует символам английского алфавита в верхнем и нижнем регистрах, цифрам и символу подчеркивания. Это множество принято также называть «символами слова».

(**)   Несмотря на название, в действительности символ \b определяется как позиция между символами, по одну сторону от которой расположены символы множества \w, а по другую – символы дополнения этого множества. Например, в результате вычисления функции preg_match_all("/(\b\w+\b)/", "38-years-old", $match) массив $match получит значение ("38", "years", "old")

Вернуться назад

Рейтинг@Mail.ru

Яндекс.Метрика

Индекс цитирования

Рейтинг Сайтов ДОСКИ.РУ