Регулярные выражения для чайников
Категория: / DEV Блог
/ PHP (LAMP)
Что такое регулярные выражения?
В народе: регэкспы, регулярки.
По-простому - это выражения для поиска и замены подстроки по шаблону.
В PHP используется название PCRE (Perl Compatible Regular Expressions -
перл совместимые регулярные выражения). В этой статье я постараюсь раскрыть
потенциал это мощного инструмента программиста. Не пытайтесь понять все сразу,
впитывайте порциями и приходите за добавкой.
Начнем
Создадим строку
Если нам нужно просто узнать есть ли шаблон 'abc' в строке $string
мы можем набросать такой код:
Этот код выведет '1'. Потому что он нашел 1 (одно) вхождение шаблона в строке.
Если шаблон в строке не обнаружен, preg_match вернет 0. При нахождении первого вхождения,
функция сразу возвращает результат! Дальнейший поиск не продолжается (см. preg_match_all)
Нахождение начала строки
Теперь мы желаем узнать, начинается ли строка с 'abc'.
Символ начала строки в регулярках - '^' (caret - знак вставки).
Пример:
Пример выведет:
The string begins with abc
Оборачивающие слэши - разделители, содержат регуряное выражение. Это могут быть любые парные символы,
например @regex@, #regex#, /regex/ и .т.п.
Символ ^ сразу после первого разделителя указывает что выражение начинается сначала строки и НИКАК иначе.
Что делать с регистром символов (строчные-прописные)
Перепишем код, чтобы он искал строку 'ABC':
Скрипт вернет:
Не думаю
Все потому что поиск регистро-зависимый. Шаблон 'abc' не тоже самое что 'ABC'.
Чтобы найти оба варианта, нужно использовать модификатор. В регулярных выражениях
для этого применяется модификатор 'i', который нужно указать за закрывающим разделителем
регулярного выражения.
Теперь скрипт найдет паттерн 'abc'. Также теперь будут попадать под шаблон
строки вида abc, ABC, Abc, aBc, и т.п.
Позже будет рассказано подробнее о модификаторах.
Как указать в паттерне конец строки
Делается это также как и в случае с поиском начала строки.
Распространенная ошибка, допускаемя многими прогерами - использование символа $ для указания конца строки в шаблоне.
Это неверно, правильное решение - использовать утверждение \z. Посмотрите на этот код
Сниппет вернет true, потому что $ = \Z, что в свою очередь можно описать выражением (?=\z|\n\z).
Когда нам нужно получить в результате строку без "разделителей строк", $ не должен использоваться.
Также $ совпададет больше одного раза с модификатором /m, в противоположность \z. Изменим немного код,
удалим каретку (^) в начале паттерна и добавим \z в конце, также уберем зависимость от регистра модификатором /i.
Результат скрипта:
>> Совпадение, строка заканчивается на 89
Потому что мы определили конец строки 89. Вот так.
Мета символы
Ранее мы поэкспериментировали с простыми регулярками. Познакомились с кареткой (^) и долларом ($)/
Эти символы имееют особенное значение. Каретка (^) обозначает начало страки и доллар ($) - ее конец.
Такие символы в купе с остальными специальными называются мета символами (meta characters).
Список мета символов в регулярных выражениях:
Разберем все символы на примерах.
Если вам нужно составить шаблон в котором содержится такой символ, его необходимо экранировать (см. preg_quote)
Например шаблон: "1+1", нужно записать как-то так:
Результат скрипта:
The string begins with 1+1
Потому что интерпретатор проигнорировал специальное значение символа "+", обозначенного символом экранирования "\" (бэкслэш).
Если бы мы не добавили экран к плюсу, то preg_match("/^1+1/i", $string) не нашло бы совпадений с шаблоном.
Сам бэкслэш в свою очередь тоже нужно экранировать, если мы ищем именно этот символ "\\".
Что означают остальные мета символы
Квадратные скобки [ ] обозначают "строковой класс".
Символьный класс. Это просто набор символов, которые должны совпасть в искомой строке.
Они могут записываться индивидуально (по одному):
[abcdef]
Или как диапазон, разделенный символом "-":
[a-f]
Результат скрипта:
return 1
Потому что preg_match() нашел совпадение.
Этот код также найдет совпадение со строками 'bag' 'bog' 'big', но не с 'beg'.
Диапазон символов [a-f] равнозначен такой записи [abcdef]. Словами формулируется так [от 'a' до 'f'].
Еще раз повторю, выражения регистрозависимые, и [A-F] не тоже самое что и [a-f].
Мета символы не работыют внутри классов, поэтому их не нужно экранировать внутри квадратных скобок [...].
Например класс [abcdef$] совпадет с символами a b c d e f $. Доллар ($) внутри класса - это простойбакс знак доллара без какого либо специального мета-свойства.
Есть правда исключения из правил:
Одна из полезных функций регулярных выражений - возможность указать шаблон НЕ совпадающий с диапазоном символов.
Чтобы это сделать, нужно использовать каретку (^) первым символом класса.
Найдем любые символы, кроме "b":
Результат скрипта:
0 -> a
Здесь preg_match() нашел первое совпадение с шаблоном /[^b]/.
Изменим скрипт и используем preg_match_all() для нахождения всех вхождений соответствующих шаблону /[^b]/.
Результат скрипта:
acefghijklmnopqrstuvwxyz0123456789
Выведет все символы, которые НЕ совпадают с шаблоном "b".
Так мы можем отфильтровать все цифры в строке:
Результат скрипта:
abcefghijklmnopqrstuvwxyz
Шаблон [^0-9] расшифровывается как все НЕ включая цифры от 0 до 9.
Продолжаете слушать нашу радиостанцию?
Тогда продолжим.
Метасимвол Бэкслэш (\).
Основное значение - экранирование других метасимволов.
Результат скрипта:
[]
Здесь мы хотели найти все символы []. Без экранирования шаблон выглядел бы так - "/[[]]/",
но мы добавили бэеслэши к скобкам [], чтобы отменить их мета-статус.
Также, к примеру, поступим с путем к файлу.
c:\dir\file.php
В паттерне будем использовать разделитель "\\".
Бэкслэш также ортодоксально используется в строках для указания специальных последовательностей: \n, \r и др.
Еще он неймспейсы разделяет!
Следующий символ "." (точка) ака "полный стоп".
`Точка` совпадает с любым символом кроме символов разрыва строки \r или \n.
С помощью точки мы можем найти любой одиночный символ, за исключением разрыва строки.
Чтобы точка также совпадала с переводом каретки и разрывом строки, можно использовать флаг /s.
Ищем одиночный символ
Результат скрипта:
1
Да, да preg_match() нашел одно совпадение. Пример также сработает с sax, six, sox, sux, и s x, но не совпадет с "stix".
Теперь попробуем найти \n.
Результат скрипта:
sex
at
noon
taxes
4
preg_match_all() нашел 4 совпадения разрыва строки "\n" потому что мы использовали флаг \s. Подробнее про флаге в разделе Спец Последовательностей..
Следующий волшебный символ - звездочка (*) asterisk
Совпадает с НОЛем и/или БОЛЕЕ вхождений шаблона, находящегося перед звездочкой.
* означает опциональный шаблон - допускается что символы могут быть, а могут и отсутствовать в строке.
Так шаблон .* совпадает с любым количеством любых символов. Пример:
Результат скрипта:
1
Нашлось одно совпадение. В примере это один символ "h".
Пример также совпадет также со строкой "pp" (ноль символов "h"), и "phhhp" (три символа "h").
Добрались до мета символа символа "+"
Плюс почти тоже самое что и звездочка, за исключением того что плюс совпадает с ОДНИМ и БОЛЬШЕ символом.
Так в примере звездочка "*" совпала со строкой 'pp', с плюсом "+" такое не пройдет.
Результат скрипта:
0
Потому что ни одного символа "h".
Следубщий пациент
Мета символ "?"
Знак вопроса совпадет с НУЛЕМ или ОДНИМ вхождением символа или регулярным выражением,
указанным сразу перед ним. Полезен для указания опциональных символов (которых может и не быть).
Например, телефонный номер в Австралии: 1234-5678.
Результат скрипта:
1
Потому что -? совпал 0 раз с символом "-". Изменение строки на "1234-5678" выдаст тот же результат.
Фигурные скобки {}
Указывает на количество совпавших символов или их интервал.
Например, за фразой PHP должно следовать ТОЧНО ТРИ цифры:
Результат скрипта:
1
Шаблон PHP 0-9(цифры от 0 до 9) {3} (три раза) совпал.
Специальные последовательности
Бэкслэш (\) используется для спец. последовательностей:
* \d - любая цифра (тоже самое что и [0-9])
* \D - любая НЕ цифра ([^0-9])
* \s - все "недосимволы" - пробелы, переводы строки, табуляция ([ \t\n\r\f\v])
* \S - все НЕ "недосимволы" ([^ \t\n\r\f\v])
* \w - все альфа-цифровые символы (буквенно-числовые) ([a-zA-Z0-9_])
* \W - все НЕ альфа-цифровые символы ([^a-zA-Z0-9_])
Итак, используя последофательности (флаги) мы можем сократить наши регулярные выражения
и улучшить их читабельность.
Результат скрипта:
abcefghijklmnopqrstuvwxyz0123456789
Мы нашли (preg_match_all) все цифры и буквы (\w) класса ( [] ).
На следующем примере мы можем убедиться, что строка не содержит чисел.
Метасимвол "." (Точка, полный стоп)
Совпадает один раз с любым символом (кроме разрыва строки)
Результат скрипта:
The string contains at least on character
Конечно, код содержит хотябы один символ.
Ранее была рассмотрена проблема нахождения символа разрыва строки, потому что "." не совпадает с таким символом (\n).
Здесь нам на помощь придет флаг \s. Он найдет любой пробельный символ (недосимвол).
Для примера используем \n.
Результат скрипта:
sex
at
noon
taxes
4
preg_match() нашел 4 совпадения перевода строки \n.
Теперь все вместе, хором
Более сложные выражения.
Рассмотрим оператор OR (ИЛИ).
В регулярных выражениях это символ "|" (труба, канал).
Настало время показательного "Hello World" скрипта.
Усложним задачу: попытаемся найти одновременно Hello или Jello в строке.
Хотя шаблон совпал, мы не видим какую имеено сроку мы нашли.
Для возвращения найденных результатов в preg_match добавляется третий параметр (&$matches):
Результат скрипта:
0->Hello
1->He
Элемент массив $matches[0] содержит всю совпавшую подстроку (всегда), в примере - Hello.
Последующие элементы содержат последовательно вхождения субпаттернов "()".
$matches[1] совпадает с первым субпатерном. В примере - (Je|He)
Модификаторы и утверждения
Модификаторы изменяют поведения шаблонов регулярных выражений.
Простой пример модификатора "i"
Использование модификатора "s"
Результат скрипта:
0
"." не находит символы разрыва строки, добавим модификатор "s"
чтобы это исправить
Результат скрипта:
1
Разрывы строк позволяют нам использовать модификатор "m".
Это улично-магический модификатор. Он принимает строку за однострочнкую с символом разрыва на конце,
даже если в строке на самом деле больше символов разрыва (мультистрока).
Т.е. если в строке нет символов разрыва строк, этот модификатор ничего не значит.
Результат скрипта:
Pattern Found
Конечно регулярное выражение найдет совпадение.
Все что следует после первого символа разрыва строки отбрасывается из-за модификатора "m".
В примере используюся вместе модификаторы "i" и "m", их действие комбинируется.
"x" модификатор позволяет составлять регулярное выражение на нескольких строках,
что повышает его читабельность и позволяет добавлять комментарии внутри шаблона.
Код в пояснениях не нуждается, он просто демонстрирует как можно вставить комментарии и
написать выражение в несколько строк.
Модификатор "e"
Спец млжификатор, который изменяет выполнение сопоставления шаблону. Ниже будет выделена целая секция для его описания.
Модификатор "S"
Этот модификатор позволяет нам проанализировать строку до сопостовления с шаблонами,
которые не помечены якорями. Т.е. если шаблон не имеет начальной фиксированой позиции, как например:
Паттерн может успорить выполение шаблона в случае с множественными совпадениями.
В следующем примере появляется множественное вхождение шаблона, поэтому добавим "S".
Результат скрипта:
abcefghijklmnopqrstuvwxyz01234567890
На практике модификатор используется достаточно редко.
Модификатор границы слова (word boundary) "\b"
Граница слова создается между двух "\b" модификаторов.
Это специальный "подпирающий тип модификаторов, которые позволяют указть ТОЧНОЕ совпадение.
Текст должен совпасть только с точным шаблоном заключенным в "\b"
Например, шаблон "cat" не совпадет с "catalog".
Результат скрипта:
Не думаю
Мы пытаемся найти совпадение с паттерном "lab", которое находится внутри строки в слове "available".
Из за использования границ слов, шаблон не совпал с подстрокой.
Давайте попробуем пример, не используя модификатора границ слов.
Результат скрипта:
eregi will remain in the computer lab
Мы видим что совпадение произошло с целым словом "lab". (\blab\b).
Модификатор \B
Этот модификатор относится к предыдущем, но \B не ставит условия гранц слова, а наоборот
отрицает границу слов. Этот модификатор полезен, когда нужно найти что-нибудь внутри
текста, который находится внутри слова, но не в самом начале или конце фразы.
Результат скрипта:
>> Совпал шаблон "the".
Этот код сначала найдет паттерн "the". Потому что сначала указан модификатор "не граница слова",
the находится внутри фразы и не снача ее, затем модификатор \b границы указывает что фраза должна
закончится на -the.
Результат скрипта:
Не думаю
В этот раз мы ничего не нашли, потому что "the" стоит на границе слова, а мы использовали модификатор \B.
Последний модификатор - \U
По умолчанию, PCRE "жадный" - это не значит что они съедят вашу печеньку,
а означает что шаблон совпадет с наибольшим возможным количеством символов,
попадающих под этот шаблон.
Чтобы отключить такую "жадность" регулярных выражений
- используем ограничитель "?", например "(.*?)"
- используем модификатор "\U".
Новичкам желательно использовать этот модификатор по-умолчанию, чтобы не возникало конфузов.
Результат скрипта:
Совпадение
Другой пример - дан кусок html
Попытаемся найти все ссылки выражением preg_match_all("/<a href="#\d+">.*</a>/s", $string),
код вернет всю искомую строку вместо трех ссылок. Добавив Нежадный модификатор, все три ссылки поотдельности.
Вычисление с preg_replace
Приветствуем на сцене модификатор "e".
Этот модификатор вычисляет заменяемый аргумент.
До этого мы не рассматривали preg_replace(), поэтому быстрый пример:
Пример заменит в строке foo на bar. В таких простых заменах целесообразнее использовать функции обработки строк
str_replace(), которые быстрее справляются с простыми задачами, но имеют некоторые ограничения, например не поддерживают юникод.
Без модификатора "е" скрипты выдаст результат:
This is a $template_vars[FOO] and this is a $template_vars[BAR]
С модификатором переменные вычислятся после замены:
This is the The PHP Way bought to you by PHPro.orG
Таким образом, модификатор "e" обладает потенциалом встроенного шаблонизатора.
Заглядывание вперед (Look Aheads)
Возможность регулярных выражений "заглянуть вперед" шаблона для определения дальнейших совпадений.
"Подглядывание вперед" бывает положительное и отрицательное
Рассмотрим сначала заглядывание вперед с отрицанием. Обозначается в шаблоне символами "?!".
Полезно при поиске шаблона, стоящего впереди от совпадения, которое нам нужно.
Пример:
Результат скрипта:
No match is found
Потому что слово "white" следует за словом "house".
Подадим блюдо под другим соусом:
Результат скрипта:
Совпадение
Есть совпадение, потому что слово "white" не следует сразу же за словом "house" (как в "whitehouse")
Позитивное/положительное заглядывание вперед "?="
Результат скрипта:
Array { [0]=>'eg' }
Код ищет паттерн "eg", стоящий перед ":" двоеточием.
Но что если нам нужно найти что-то до двоеточия, например дом из предудыщего примера.
Для этого на помощь приходят "заглядывания назад".
Заглядывание назад (Look Behinds)
Позволяет просмотреть строку назад и определить наличие совпадений с шаблоном.
Также разделяется на положительное и отрицательное.
Положительное - записывается "?<="
Разберем пример:
Результат скрипта:
Совпадение
Здесь мы нашли совпадение, потому что паттерн "house" сразу следует за паттерном "house".
Движок регулярных выражений "посмотрел назад" шаблона "house" и определил совпадение.
Если мы хотим, чтобы "house" НЕ следовал за словом "white"?
Используем отрицительное заглядывание назад - "?<!"
Результат скрипта:
no match is found
Потому что отрицательное заглядывание не нашло шаблона "house" c шаблоном "white" в начале его.
Давайте поменяем цвет "дома", белым слишком девственный для правительственного здания.
Мы изменили "whitehouse" на "bluehouse" и теперь наша регулярка сработала, потому что
шаблон "white" не обнаружен перед "house".
По-умолчанию регулярки жадные, это значит что квантификаторы (какое слово страшное)
*, +, ? "пожирают" столько символов сколько могут.
Пример
Первый паттерн (.*) совпал со всеми четыремя "x" и тремя из четырех символов "z".
Сработала жадность - шаблон забрал столько символов, сколько было в искомой строке.
Проще простого помочь перестать квантификаторам быть жадными, добавив "?" к квантификатору как в примере:
Теперь $matches[1] содержит четыре "x" символа и $matches[2] четыре символа "z".
Потому что квантификатор "?" изменил поведение шаблона с "взять как можно БОЛЬШЕ" на "взять как можно МЕНЬШЕ".
Чтобы сделать нежадным весь шаблон, используем модификатор "U".
Результат как в предыдущем примере.
Подводные камни c ? и U
Важно заметить, что модификатор "U" не только делает поиск нежадным, он инвертирует поведение жадности квантификатора "?".
Если использовался квантификатор "?" и одновременно модификатор "U", действие "?" будет инвертировано.
Результат скрипта:
xxxxzzz
Delimiters
В этом мане было рассмотрено много регулярок и все они разделялись слэшем "/".
Иногда нам нужно находить в шаблоне слэш и когда он одновременно является разделителем регуляного выражения,
нам придется экранировать каждый встречающийся слэш, что неудобно.
Поэтому в качестве разделителя можно взять любой символ, например #, @, ^ и т.п.
Автор текста: Kevin Waterson Ссылка на ориганал phppro.org
Примеры
Запомните, preg_match() возвращает только 0 или 1, и останавливается после первого успешного нахождения шаблона.
Чтобы найти все совпадения - используйте preg_match_all().
Чит Шит
Дополнения от меня
Posix символьные классы
Дополнительные шорткуты для шаблонов. Могут применяться только внутри классов.
Пример для поиска числа с пробелами - preg_match("@[[:space:]\d]+@", $string)
Внутренние модификаторы шаблонов
Модификаторы m, s, x, U, X, J могут использоваться внутри шаблона.
Например (?im) установит мультистроковой регистронезивисимый метод поиска для паттерна.
Отключить внутренние модификаторы можно перечислив их через дефис, например (?im-sx)
Пример:
шаблон (?i:foo) совпадет с "FoO"
Именованный "захват"
Возможность регулярных выражений именовать ключи в результирующем массиве совпадений.
Записывается: (?<name>), (?'name') или (?P<name>).
Раньше поддерживался только такой синтаксис: (?P<name>). [<php5.2.2]
Результат скрипта:
array('Name' => 'строка', 'Age' => 'число')
Замена через callback-функцию
В php есть возможность указать функцию обратного вызова
для совпадений, если нам нужно проделать с ними необычные вещи.
Для этого используется preg_replace_callback.
Раcсмотрим пример
Данный код заменит все первые буквы в параграфах на заглавные.
В php >= 5.3 callback-функцию можно записать в сокращенном виде
Смотрите также
Логические операции в регулярных выражениях
Боремся с кириллицей и юникодом
В народе: регэкспы, регулярки.
По-простому - это выражения для поиска и замены подстроки по шаблону.
В PHP используется название PCRE (Perl Compatible Regular Expressions -
перл совместимые регулярные выражения). В этой статье я постараюсь раскрыть
потенциал это мощного инструмента программиста. Не пытайтесь понять все сразу,
впитывайте порциями и приходите за добавкой.
Начнем
Создадим строку
<?php
// наша строка для испытаний
$string = 'abcdefghijklmnopqrstuvwxyz0123456789';
// вывод
echo $string;
?>
Если нам нужно просто узнать есть ли шаблон 'abc' в строке $string
мы можем набросать такой код:
<?php
$string = 'abcdefghijklmnopqrstuvwxyz0123456789';
echo preg_match("/abc/", $string);
?>
Этот код выведет '1'. Потому что он нашел 1 (одно) вхождение шаблона в строке.
Если шаблон в строке не обнаружен, preg_match вернет 0. При нахождении первого вхождения,
функция сразу возвращает результат! Дальнейший поиск не продолжается (см. preg_match_all)
Нахождение начала строки
Теперь мы желаем узнать, начинается ли строка с 'abc'.
Символ начала строки в регулярках - '^' (caret - знак вставки).
Пример:
<?php
$string = 'abcdefghijklmnopqrstuvwxyz0123456789';
// тест на начало строки
if(preg_match("/^abc/", $string))
{
// окей, строка начинается с абс
echo 'The string begins with abc';
}
else
{
echo 'это фэйл';
}
?>
Пример выведет:
The string begins with abc
Оборачивающие слэши - разделители, содержат регуряное выражение. Это могут быть любые парные символы,
например @regex@, #regex#, /regex/ и .т.п.
Символ ^ сразу после первого разделителя указывает что выражение начинается сначала строки и НИКАК иначе.
Что делать с регистром символов (строчные-прописные)
Перепишем код, чтобы он искал строку 'ABC':
<?php
$string = 'abcdefghijklmnopqrstuvwxyz0123456789';
echo preg_match("/^ABC/", $string) ? 'Совпадение' : 'Не думаю';
?>
Скрипт вернет:
Не думаю
Все потому что поиск регистро-зависимый. Шаблон 'abc' не тоже самое что 'ABC'.
Чтобы найти оба варианта, нужно использовать модификатор. В регулярных выражениях
для этого применяется модификатор 'i', который нужно указать за закрывающим разделителем
регулярного выражения.
<?php
$string = 'abcdefghijklmnopqrstuvwxyz0123456789';
if (preg_match("/^ABC/i", $string)) {
echo 'Совпадение, строка начинается с abc';
} else {
echo 'Не думаю';
}
?>
Теперь скрипт найдет паттерн 'abc'. Также теперь будут попадать под шаблон
строки вида abc, ABC, Abc, aBc, и т.п.
Позже будет рассказано подробнее о модификаторах.
Как указать в паттерне конец строки
Делается это также как и в случае с поиском начала строки.
Распространенная ошибка, допускаемя многими прогерами - использование символа $ для указания конца строки в шаблоне.
Это неверно, правильное решение - использовать утверждение \z. Посмотрите на этот код
<?php
echo preg_match("/^foo$/", "foo\n");
?>
Сниппет вернет true, потому что $ = \Z, что в свою очередь можно описать выражением (?=\z|\n\z).
Когда нам нужно получить в результате строку без "разделителей строк", $ не должен использоваться.
Также $ совпададет больше одного раза с модификатором /m, в противоположность \z. Изменим немного код,
удалим каретку (^) в начале паттерна и добавим \z в конце, также уберем зависимость от регистра модификатором /i.
<?php
$string = 'abcdefghijklmnopqrstuvwxyz0123456789';
// паттерн в конце строки?
if (preg_match("/89\z/i", $string)) {
echo 'Совпадение, строка заканчивается на 89';
} else {
echo 'Не думаю';
}
?>
Результат скрипта:
>> Совпадение, строка заканчивается на 89
Потому что мы определили конец строки 89. Вот так.
Мета символы
Ранее мы поэкспериментировали с простыми регулярками. Познакомились с кареткой (^) и долларом ($)/
Эти символы имееют особенное значение. Каретка (^) обозначает начало страки и доллар ($) - ее конец.
Такие символы в купе с остальными специальными называются мета символами (meta characters).
Список мета символов в регулярных выражениях:
. (Точка, Full stop)
^ (Каретка, Carat)
* (Звездочка, Asterix)
+ (Plus)
? ( Question Mark)
{ ( Opening curly brace)
[ (Opening brace)
] (Closing brace)
\ (Backslash)
| (Труба, Pipe)
( (Opening parens)
) (Closing parens)
} (Closing curly brace)
?>
Разберем все символы на примерах.
Если вам нужно составить шаблон в котором содержится такой символ, его необходимо экранировать (см. preg_quote)
Например шаблон: "1+1", нужно записать как-то так:
<?php
// образец
$string = '1+1=2';
if (preg_match("/^1\+1/i", $string)) {
// yep
echo 'The string begins with 1+1';
} else {
// nope
echo 'Не думаю';
}
?>
Результат скрипта:
The string begins with 1+1
Потому что интерпретатор проигнорировал специальное значение символа "+", обозначенного символом экранирования "\" (бэкслэш).
Если бы мы не добавили экран к плюсу, то preg_match("/^1+1/i", $string) не нашло бы совпадений с шаблоном.
Сам бэкслэш в свою очередь тоже нужно экранировать, если мы ищем именно этот символ "\\".
Что означают остальные мета символы
Квадратные скобки [ ] обозначают "строковой класс".
Символьный класс. Это просто набор символов, которые должны совпасть в искомой строке.
Они могут записываться индивидуально (по одному):
[abcdef]
Или как диапазон, разделенный символом "-":
[a-f]
<?php
$string = 'big';
// Ищем шаблон
echo preg_match("/b[aoiu]g/", $string, $matches);
?>
Результат скрипта:
return 1
Потому что preg_match() нашел совпадение.
Этот код также найдет совпадение со строками 'bag' 'bog' 'big', но не с 'beg'.
Диапазон символов [a-f] равнозначен такой записи [abcdef]. Словами формулируется так [от 'a' до 'f'].
Еще раз повторю, выражения регистрозависимые, и [A-F] не тоже самое что и [a-f].
Мета символы не работыют внутри классов, поэтому их не нужно экранировать внутри квадратных скобок [...].
Например класс [abcdef$] совпадет с символами a b c d e f $. Доллар ($) внутри класса - это простой
Есть правда исключения из правил:
Одна из полезных функций регулярных выражений - возможность указать шаблон НЕ совпадающий с диапазоном символов.
Чтобы это сделать, нужно использовать каретку (^) первым символом класса.
Найдем любые символы, кроме "b":
<?php
$string = 'abcefghijklmnopqrstuvwxyz0123456789';
// осуществляем поиск
preg_match("/[^b]/", $string, $matches);
// выведем все совпадения в цикле foreach
foreach ($matches as $key => $value) {
echo $key.' -> '.$value;
}
?>
Результат скрипта:
0 -> a
Здесь preg_match() нашел первое совпадение с шаблоном /[^b]/.
Изменим скрипт и используем preg_match_all() для нахождения всех вхождений соответствующих шаблону /[^b]/.
<?php
$string = 'abcefghijklmnopqrstuvwxyz0123456789';
// ищем ВСЕ совпадения
preg_match_all("/[^b]/", $string, $matches);
// выведем все совпадения в цикле foreach
foreach ($matches[0] as $value) {
echo $value;
}
?>
Результат скрипта:
acefghijklmnopqrstuvwxyz0123456789
Выведет все символы, которые НЕ совпадают с шаблоном "b".
Так мы можем отфильтровать все цифры в строке:
<?php
$string = 'abcefghijklmnopqrstuvwxyz0123456789';
// все символы не являющиеся цифрами от 0 до 9
preg_match_all("/[^0-9]/", $string, $matches);
foreach ($matches[0] as $value) {
echo $value;
}
?>
Результат скрипта:
abcefghijklmnopqrstuvwxyz
Шаблон [^0-9] расшифровывается как все НЕ включая цифры от 0 до 9.
Продолжаете слушать нашу радиостанцию?
Тогда продолжим.
Метасимвол Бэкслэш (\).
Основное значение - экранирование других метасимволов.
<?php
// create a string
$string = 'This is a [templateVar]';
// try to match our pattern
preg_match_all("/[\[\]]/", $string, $matches);
// loop through the matches with foreach
foreach ($matches[0] as $value) {
echo $value;
}
?>
Результат скрипта:
[]
Здесь мы хотели найти все символы []. Без экранирования шаблон выглядел бы так - "/[[]]/",
но мы добавили бэеслэши к скобкам [], чтобы отменить их мета-статус.
Также, к примеру, поступим с путем к файлу.
c:\dir\file.php
В паттерне будем использовать разделитель "\\".
Бэкслэш также ортодоксально используется в строках для указания специальных последовательностей: \n, \r и др.
Еще он неймспейсы разделяет!
Следующий символ "." (точка) ака "полный стоп".
`Точка` совпадает с любым символом кроме символов разрыва строки \r или \n.
С помощью точки мы можем найти любой одиночный символ, за исключением разрыва строки.
Чтобы точка также совпадала с переводом каретки и разрывом строки, можно использовать флаг /s.
Ищем одиночный символ
<?php
$string = 'sex at noon taxes';
echo preg_match("/s.x/", $string, $matches);
?>
Результат скрипта:
1
Да, да preg_match() нашел одно совпадение. Пример также сработает с sax, six, sox, sux, и s x, но не совпадет с "stix".
Теперь попробуем найти \n.
<?php
// create a string
$string = 'sex'."\n".'at'."\n".'noon'."\n".'taxes'."\n";
// echo the string
echo nl2br($string);
// look for a match
echo preg_match_all("/\s/", $string, $matches);
?>
Результат скрипта:
sex
at
noon
taxes
4
preg_match_all() нашел 4 совпадения разрыва строки "\n" потому что мы использовали флаг \s. Подробнее про флаге в разделе Спец Последовательностей..
Следующий волшебный символ - звездочка (*) asterisk
Совпадает с НОЛем и/или БОЛЕЕ вхождений шаблона, находящегося перед звездочкой.
* означает опциональный шаблон - допускается что символы могут быть, а могут и отсутствовать в строке.
Так шаблон .* совпадает с любым количеством любых символов. Пример:
<?php
// create a string
$string = 'php';
// look for a match
echo preg_match("/ph*p/", $string, $matches);
?>
Результат скрипта:
1
Нашлось одно совпадение. В примере это один символ "h".
Пример также совпадет также со строкой "pp" (ноль символов "h"), и "phhhp" (три символа "h").
Добрались до мета символа символа "+"
Плюс почти тоже самое что и звездочка, за исключением того что плюс совпадает с ОДНИМ и БОЛЬШЕ символом.
Так в примере звездочка "*" совпала со строкой 'pp', с плюсом "+" такое не пройдет.
<?php
// create a string
$string = 'pp';
// look for a match
echo preg_match("/ph+p/", $string, $matches);
?>
Результат скрипта:
0
Потому что ни одного символа "h".
Следубщий пациент
Мета символ "?"
Знак вопроса совпадет с НУЛЕМ или ОДНИМ вхождением символа или регулярным выражением,
указанным сразу перед ним. Полезен для указания опциональных символов (которых может и не быть).
Например, телефонный номер в Австралии: 1234-5678.
<?php
// create a string
$string = '12345678';
// look for a match
echo preg_match("/1234-?5678/", $string, $matches);
?>
Результат скрипта:
1
Потому что -? совпал 0 раз с символом "-". Изменение строки на "1234-5678" выдаст тот же результат.
Фигурные скобки {}
Указывает на количество совпавших символов или их интервал.
Например, за фразой PHP должно следовать ТОЧНО ТРИ цифры:
<?php
// create a string
$string = 'PHP123';
// look for a match
echo preg_match("/PHP[0-9]{3}/", $string, $matches);
?>
Результат скрипта:
1
Шаблон PHP 0-9(цифры от 0 до 9) {3} (три раза) совпал.
Специальные последовательности
Бэкслэш (\) используется для спец. последовательностей:
* \d - любая цифра (тоже самое что и [0-9])
* \D - любая НЕ цифра ([^0-9])
* \s - все "недосимволы" - пробелы, переводы строки, табуляция ([ \t\n\r\f\v])
* \S - все НЕ "недосимволы" ([^ \t\n\r\f\v])
* \w - все альфа-цифровые символы (буквенно-числовые) ([a-zA-Z0-9_])
* \W - все НЕ альфа-цифровые символы ([^a-zA-Z0-9_])
Итак, используя последофательности (флаги) мы можем сократить наши регулярные выражения
и улучшить их читабельность.
<?php
// create a string
$string = 'ab-ce*fg@ hi & jkl(mnopqr)stu+vw?x yz0>1234<567890';
// match our pattern containing a special sequence
preg_match_all("/[\w]/", $string, $matches);
// loop through the matches with foreach
foreach ($matches[0] as $value) {
echo $value;
}
?>
Результат скрипта:
abcefghijklmnopqrstuvwxyz0123456789
Мы нашли (preg_match_all) все цифры и буквы (\w) класса ( [] ).
На следующем примере мы можем убедиться, что строка не содержит чисел.
<?php
// create a string
$string = '2 bad for perl';
// echo our string
if (preg_match("/^\d/", $string)) {
echo 'String begins with a number';
} else {
echo 'String does not begin with a number';
}
?>
Метасимвол "." (Точка, полный стоп)
Совпадает один раз с любым символом (кроме разрыва строки)
<?php
// create a string
$string = 'abcdefghijklmnopqrstuvwxyz0123456789';
// try to match any character
if (preg_match("/./", $string)) {
echo 'The string contains at least on character';
} else {
echo 'String does not contain anything';
}
?>
Результат скрипта:
The string contains at least on character
Конечно, код содержит хотябы один символ.
Ранее была рассмотрена проблема нахождения символа разрыва строки, потому что "." не совпадает с таким символом (\n).
Здесь нам на помощь придет флаг \s. Он найдет любой пробельный символ (недосимвол).
Для примера используем \n.
<?php
// create a string
$string = 'sex'."\n".'at'."\n".'noon'."\n".'taxes'."\n";
// echo the string
echo nl2br($string);
// look for a match
echo preg_match_all("/\s/", $string, $matches);
?>
Результат скрипта:
sex
at
noon
taxes
4
preg_match() нашел 4 совпадения перевода строки \n.
Теперь все вместе, хором
Более сложные выражения.
Рассмотрим оператор OR (ИЛИ).
В регулярных выражениях это символ "|" (труба, канал).
Настало время показательного "Hello World" скрипта.
<?php
// a simple string
$string = "This is a Hello World script";
// try to match the patterns This OR That OR There
echo preg_match("/^(This|That|There)/", $string);
?>
Усложним задачу: попытаемся найти одновременно Hello или Jello в строке.
<?php
// a simple string
$string = "This is a Hello World script";
// try to match the patterns Jello or Hello
if (!preg_match("/(Je|He)llo/", $string)) {
echo 'Pattern not found';
} else {
echo 'pattern found';
}
?>
Хотя шаблон совпал, мы не видим какую имеено сроку мы нашли.
Для возвращения найденных результатов в preg_match добавляется третий параметр (&$matches):
<?php
// a simple string
$string = "This is a Hello World script";
// try to match the patterns Jello or Hello
// put the matches in a variable called matches
preg_match("/(Je|He)llo/", $string, $matches);
// loop through the array of matches and print them
foreach ($matches as $key => $value) {
echo $key.'->'.$value.'<br />';
}
?>
Результат скрипта:
0->Hello
1->He
Элемент массив $matches[0] содержит всю совпавшую подстроку (всегда), в примере - Hello.
Последующие элементы содержат последовательно вхождения субпаттернов "()".
$matches[1] совпадает с первым субпатерном. В примере - (Je|He)
Модификаторы и утверждения
Модификаторы изменяют поведения шаблонов регулярных выражений.
Модификаторы
i - регистронезависимый (Ignore Case, case insensitive)
U - нежадный поиск (Make search ungreedy)
s - включая перевод строки (Includes New line)
m - мультистрока (Multiple lines)
x - Extended for comments and whitespace
e - Enables evaluation of replacement as PHP code. (preg_replace only)
S - Extra analysis of pattern
Утверждения (Assertions)
b - граница слова (Word Boundry)
B - НЕ граница слова (Not a word boundary)
A - начало шаблона (Start of subject)
Z - конец шаблона или разрыв строки (End of subject or newline at end)
z - конец шаблона (End of subject)
G - первая совпавшая позиция в шаблоне (First matching position in subject)
?>
Простой пример модификатора "i"
<?php
// create a string
$string = 'abcdefghijklmnopqrstuvwxyz0123456789';
// try to match our pattern
if (preg_match("/^ABC/i", $string)) {
echo 'Совпадение, строка начинается с abc';
} else {
echo 'Не думаю';
}
?>
?>
Использование модификатора "s"
<?php
/*** create a string with new line characters ***/
$string = 'sex'."\n".'at'."\n".'noon'."\n".'taxes'."\n";
/*** look for a match */
echo preg_match("/sex.at.noon/", $string, $matches);
?>
Результат скрипта:
0
"." не находит символы разрыва строки, добавим модификатор "s"
чтобы это исправить
<?php
/*** create a string with new line characters ***/
$string = 'sex'."\n".'at'."\n".'noon'."\n".'taxes'."\n";
/*** look for a match using s modifier ***/
echo preg_match("/sex.at.noon/s", $string, $matches);
?>
?>
Результат скрипта:
1
Разрывы строк позволяют нам использовать модификатор "m".
Это улично-магический модификатор. Он принимает строку за однострочнкую с символом разрыва на конце,
даже если в строке на самом деле больше символов разрыва (мультистрока).
Т.е. если в строке нет символов разрыва строк, этот модификатор ничего не значит.
<?php
// create a string
$string = 'sex'."\n".'at'."\n".'noon'."\n".'taxes'."\n";
// look for a match
if (preg_match("/^noon/im", $string)) {
echo 'Pattern Found';
} else {
echo 'Pattern not found';
}
?>
Результат скрипта:
Pattern Found
Конечно регулярное выражение найдет совпадение.
Все что следует после первого символа разрыва строки отбрасывается из-за модификатора "m".
В примере используюся вместе модификаторы "i" и "m", их действие комбинируется.
"x" модификатор позволяет составлять регулярное выражение на нескольких строках,
что повышает его читабельность и позволяет добавлять комментарии внутри шаблона.
<?php
// create a string
$string = 'sex'."\n".'at'."\n".'noon'."\n".'taxes'."\n";
// create our regex using comments and store the regex
// in a variable to be used with preg_match
$regex ='
/ # opening double quote
^ # caret means beginning of the string
noon # the pattern to match
/imx
';
// look for a match
if (preg_match($regex, $string)) {
echo 'Pattern Found';
} else {
echo 'Pattern not found';
}
?>
Код в пояснениях не нуждается, он просто демонстрирует как можно вставить комментарии и
написать выражение в несколько строк.
Модификатор "e"
Спец млжификатор, который изменяет выполнение сопоставления шаблону. Ниже будет выделена целая секция для его описания.
Модификатор "S"
Этот модификатор позволяет нам проанализировать строку до сопостовления с шаблонами,
которые не помечены якорями. Т.е. если шаблон не имеет начальной фиксированой позиции, как например:
<?php
/*** fixed starting position ***/
preg_match("/abc(.*?)hij/", $string);
?>
Паттерн может успорить выполение шаблона в случае с множественными совпадениями.
В следующем примере появляется множественное вхождение шаблона, поэтому добавим "S".
<?php
// create a string
$string = 'ab-ce*fg@ hi & jkl(mnopqr)stu+vw?x yz0>1234<567890';
// match our pattern containing a special sequence
preg_match_all("/[\w]/S", $string, $matches);
// loop through the matches with foreach
foreach ($matches[0] as $value) {
echo $value;
}
?>
Результат скрипта:
abcefghijklmnopqrstuvwxyz01234567890
На практике модификатор используется достаточно редко.
Модификатор границы слова (word boundary) "\b"
Граница слова создается между двух "\b" модификаторов.
Это специальный "подпирающий тип модификаторов, которые позволяют указть ТОЧНОЕ совпадение.
Текст должен совпасть только с точным шаблоном заключенным в "\b"
Например, шаблон "cat" не совпадет с "catalog".
<?php
$string = 'eregi will not be available in PHP 6';
// ищем строку "lab"
if (preg_match("/\blab\b/i", $string)) {
// Совпадение
echo $string;
} else {
echo 'Не думаю';
}
?>
Результат скрипта:
Не думаю
Мы пытаемся найти совпадение с паттерном "lab", которое находится внутри строки в слове "available".
Из за использования границ слов, шаблон не совпал с подстрокой.
Давайте попробуем пример, не используя модификатора границ слов.
<?php
$string = 'eregi will remain in the computer lab';
// ищем строку "lab"
if (preg_match("/\blab\b/i", $string)) {
// Совпадение
echo $string;
} else {
echo 'Не думаю';
}
?>
Результат скрипта:
eregi will remain in the computer lab
Мы видим что совпадение произошло с целым словом "lab". (\blab\b).
Модификатор \B
Этот модификатор относится к предыдущем, но \B не ставит условия гранц слова, а наоборот
отрицает границу слов. Этот модификатор полезен, когда нужно найти что-нибудь внутри
текста, который находится внутри слова, но не в самом начале или конце фразы.
<?php
$string = 'This lathe turns wood.';
// match word boundary and non-word boundary
if (preg_match("/\Bthe\b/", $string)) {
echo 'Совпал шаблон "the".';
} else {
echo 'Не думаю';
}
?>
Результат скрипта:
>> Совпал шаблон "the".
Этот код сначала найдет паттерн "the". Потому что сначала указан модификатор "не граница слова",
the находится внутри фразы и не снача ее, затем модификатор \b границы указывает что фраза должна
закончится на -the.
<?php
$string = 'The quick brown fox jumps over the lazy dog.';
// match word boundary and non-word boundary
if (preg_match("/\Bthe\b/", $string)) {
echo 'Совпал шаблон "the".';
} else {
echo 'Не думаю';
}
?>
Результат скрипта:
Не думаю
В этот раз мы ничего не нашли, потому что "the" стоит на границе слова, а мы использовали модификатор \B.
Последний модификатор - \U
По умолчанию, PCRE "жадный" - это не значит что они съедят вашу печеньку,
а означает что шаблон совпадет с наибольшим возможным количеством символов,
попадающих под этот шаблон.
Чтобы отключить такую "жадность" регулярных выражений
- используем ограничитель "?", например "(.*?)"
- используем модификатор "\U".
Новичкам желательно использовать этот модификатор по-умолчанию, чтобы не возникало конфузов.
<?php
$string = 'foobar foo--bar fubar';
// try to match the pattern
if (preg_match("/foo(.*)bar/U", $string)) {
echo 'Совпадение';
} else {
echo 'Не думаю';
}
?>
Результат скрипта:
Совпадение
Другой пример - дан кусок html
<a href="#1">1</a>
<a href="#1">2</a>
<a href="#1">3</a>
?>
Попытаемся найти все ссылки выражением preg_match_all("/<a href="#\d+">.*</a>/s", $string),
код вернет всю искомую строку вместо трех ссылок. Добавив Нежадный модификатор, все три ссылки поотдельности.
Вычисление с preg_replace
Приветствуем на сцене модификатор "e".
Этот модификатор вычисляет заменяемый аргумент.
До этого мы не рассматривали preg_replace(), поэтому быстрый пример:
<?php
$string = 'We will replace the word foo';
// заменяем `for` на `bar`
$string = preg_replace("/foo/", 'bar', $string);
echo $string;
?>
Пример заменит в строке foo на bar. В таких простых заменах целесообразнее использовать функции обработки строк
str_replace(), которые быстрее справляются с простыми задачами, но имеют некоторые ограничения, например не поддерживают юникод.
<?php
// строка с шаблонными переменными {xxx}
$string = 'This is the {_FOO_} bought to you by {_BAR_}';
// создади массив со значениями переменных
$templateVars = ["FOO" => "The PHP Way", "BAR" => "PHPro.orG"];
// заменяем и вычисляем
$string = preg_replace("/{_(.*?)_}/ime", "\$templateVars['$1']", $string);
echo $string;
?>
Без модификатора "е" скрипты выдаст результат:
This is a $template_vars[FOO] and this is a $template_vars[BAR]
С модификатором переменные вычислятся после замены:
This is the The PHP Way bought to you by PHPro.orG
Таким образом, модификатор "e" обладает потенциалом встроенного шаблонизатора.
Заглядывание вперед (Look Aheads)
Возможность регулярных выражений "заглянуть вперед" шаблона для определения дальнейших совпадений.
"Подглядывание вперед" бывает положительное и отрицательное
Рассмотрим сначала заглядывание вперед с отрицанием. Обозначается в шаблоне символами "?!".
Полезно при поиске шаблона, стоящего впереди от совпадения, которое нам нужно.
Пример:
<?php
$string = 'I live in the whitehouse';
// try to match white not followed by house
if (preg_match("/white+(?!house)/i", $string)) {
// if we find the word white, not followed by house
echo 'Совпадение';
} else {
echo 'Не думаю';
}
?>
Результат скрипта:
No match is found
Потому что слово "white" следует за словом "house".
Подадим блюдо под другим соусом:
<?php
$string = 'I live in the white house';
// try to match white not followed by house
if (preg_match("/white+(?!house)/i", $string)) {
// if we find the word white, not followed by house
echo 'Совпадение';
} else {
echo 'Не думаю';
}
?>
Результат скрипта:
Совпадение
Есть совпадение, потому что слово "white" не следует сразу же за словом "house" (как в "whitehouse")
Позитивное/положительное заглядывание вперед "?="
<?php
$string = 'This is an example eg: foo';
// try to match eg followed by a colon
if (preg_match("/eg+(?=:)/", $string, $match)) {
print_r($match);
} else {
echo 'Нет совпадений';
}
?>
Результат скрипта:
Array { [0]=>'eg' }
Код ищет паттерн "eg", стоящий перед ":" двоеточием.
Но что если нам нужно найти что-то до двоеточия, например дом из предудыщего примера.
Для этого на помощь приходят "заглядывания назад".
Заглядывание назад (Look Behinds)
Позволяет просмотреть строку назад и определить наличие совпадений с шаблоном.
Также разделяется на положительное и отрицательное.
Положительное - записывается "?<="
Разберем пример:
<?php
$string = 'I live in the whitehouse';
// try to match house preceded by white
if (preg_match("/(?<=white)house/i", $string)) {
// if we find the word white, not followed by house
echo 'Совпадение';
} else {
echo 'Не думаю';
}
?>
Результат скрипта:
Совпадение
Здесь мы нашли совпадение, потому что паттерн "house" сразу следует за паттерном "house".
Движок регулярных выражений "посмотрел назад" шаблона "house" и определил совпадение.
Если мы хотим, чтобы "house" НЕ следовал за словом "white"?
Используем отрицительное заглядывание назад - "?<!"
<?php
/*** a simple string ***/
$string = 'I live in the whitehouse';
/*** try to match house preceded by white ***/
if(preg_match("/(?<!white)house/i", $string))
{
/*** if we find the word white, not followed by house ***/
echo 'Совпадение';
}
else
{
/*** if no match is found ***/
echo 'Не думаю';
}
?>
Результат скрипта:
no match is found
Потому что отрицательное заглядывание не нашло шаблона "house" c шаблоном "white" в начале его.
Давайте поменяем цвет "дома", белым слишком девственный для правительственного здания.
<?php
$string = 'I live in the bluehouse';
// ищем `house` с непредшествующим `white`
if (preg_match("/(?<!white)house/i", $string)) {
/*** if we find the word white, not followed by house ***/
echo 'Совпадение';
} else {
/*** if no match is found ***/
echo 'Не думаю';
}
?>
Мы изменили "whitehouse" на "bluehouse" и теперь наша регулярка сработала, потому что
шаблон "white" не обнаружен перед "house".
По-умолчанию регулярки жадные, это значит что квантификаторы (какое слово страшное)
*, +, ? "пожирают" столько символов сколько могут.
* * - 0 и больше символ, same as {0, }
* + - 1 и больше символ, same as {1, }
* ? - 0 или 1 символ, same as {0,1}
?>
Пример
<?php
/*** 4 x and 4 z chars ***/
$string = "xxxxzzzz";
/*** greedy regex ***/
preg_match("/^(.*)(z+)$/",$string,$matches);
/*** results ***/
echo $matches[1];
echo "<br />";
echo $matches[2];
?>
Первый паттерн (.*) совпал со всеми четыремя "x" и тремя из четырех символов "z".
Сработала жадность - шаблон забрал столько символов, сколько было в искомой строке.
Проще простого помочь перестать квантификаторам быть жадными, добавив "?" к квантификатору как в примере:
<?php
/*** string of characters ***/
$string = "xxxxzzzz";
/*** a non greedy match ***/
preg_match("/^(.*?)(z+)$/",$string,$matches);
/*** show the matches ***/
echo $matches[1];
echo "<br />";
echo $matches[2];
?>
Теперь $matches[1] содержит четыре "x" символа и $matches[2] четыре символа "z".
Потому что квантификатор "?" изменил поведение шаблона с "взять как можно БОЛЬШЕ" на "взять как можно МЕНЬШЕ".
Чтобы сделать нежадным весь шаблон, используем модификатор "U".
<?php
/*** string of characters ***/
$string = "xxxxzzzz";
/*** a non greedy match ***/
preg_match("/^(.*)(z+)$/U",$string,$matches);
/*** show the matches ***/
echo $matches[1];
echo "<br />";
echo $matches[2];
?>
Результат как в предыдущем примере.
Подводные камни c ? и U
Важно заметить, что модификатор "U" не только делает поиск нежадным, он инвертирует поведение жадности квантификатора "?".
Если использовался квантификатор "?" и одновременно модификатор "U", действие "?" будет инвертировано.
<?php
/*** string of characters ***/
$string = "xxxxzzzz";
/*** a non greedy match ***/
preg_match("/^(.*?)(z+)$/U",$string,$matches);
/*** show the matches ***/
echo $matches[1];
echo "<br />";
echo $matches[2];
?>
Результат скрипта:
xxxxzzz
Delimiters
В этом мане было рассмотрено много регулярок и все они разделялись слэшем "/".
Иногда нам нужно находить в шаблоне слэш и когда он одновременно является разделителем регуляного выражения,
нам придется экранировать каждый встречающийся слэш, что неудобно.
Поэтому в качестве разделителя можно взять любой символ, например #, @, ^ и т.п.
<?php
/*** get the host name from a url ***/
preg_match('#^(?:http://)?([^/]+)#i', "http://www.phpro.org/tutorials", $matches);
/*** show the host name ***/
echo $matches[1];
?>
Автор текста: Kevin Waterson Ссылка на ориганал phppro.org
Примеры
<?php
// the string to match against
$string = 'The cat sat on the mat';
// match the beginning of the string
echo preg_match("/^The/", $string);
// match the end of the string
// returns 1
echo preg_match("/mat\z/", $string);
// match anywhere in the string
// returns 0 as no match was found for dog.
echo preg_match("/dog/", $string);
?>
Поиск нескольких шаблонов
<?php
// the string to match against
$string = 'The cat sat on the matthew';
// matches the letter "a" followed by zero or more "t" characters
echo preg_match("/at*/", $string);
// matches the letter "a" followed by a "t" character that may or may not be present
echo preg_match("/at?/", $string);
// matches the letter "a" followed by one or more "t" characters
echo preg_match("/at+/", $string);
// matches a possible letter "e" followed by one of more "w" characters anchored to the end of the string
echo preg_match("/e?w+\z/", $string);
// matches the letter "a" followed by exactly two "t" characters
echo preg_match("/at{2}/", $string);
// matches a possible letter "e" followed by exactly two "t" characters
echo preg_match("/e?t{2}/", $string);
// matches a possible letter "a" followed by exactly 2 to 6 "t" chars (att attt atttttt)
echo preg_match("/at{2,6}/", $string);
?>
Запомните, preg_match() возвращает только 0 или 1, и останавливается после первого успешного нахождения шаблона.
Чтобы найти все совпадения - используйте preg_match_all().
Чит Шит
Спец последовательности
\w - Any “word” character (a-z 0-9 _)
\W - Any non “word” character
\s - Whitespace (space, tab CRLF)
\S - Any non whitepsace character
\d - Digits (0-9)
\D - Any non digit character
. - (Period) – Any character except newline
Мета символы
^ - Start of subject (or line in multiline mode)
$ - End of subject (or line in multiline mode)
[ - Start character class definition
] - End character class definition
| - Alternates, eg (a|b) matches a or b
( - Start subpattern
) - End subpattern
\ - Escape character
Квантификаторы
n- Zero or more of n
n+ - One or more of n
n? - Zero or one occurrences of n
{n} - n occurrences exactly
{n,} - At least n occurrences
{n,m} - Between n and m occurrences (inclusive)
Модификаторы
i - Case Insensitive
m - Multiline mode - ^ and $ match start and end of lines
s - Dotall - . class includes newline
x - Extended– comments and whitespace
e - preg_replace only – enables evaluation of replacement as PHP code
S - Extra analysis of pattern
U - Pattern is ungreedy
u - Pattern is treated as UTF-8
Точечные утверждения
\b - Word boundary
\B - Not a word boundary
\A - Start of subject
\Z - End of subject or newline at end
\z - End of subject
\G - First matching position in subject
Утверждения
(?=) - Positive look ahead assertion foo(?=bar) matches foo when followed by bar
(?!) - Negative look ahead assertion foo(?!bar) matches foo when not followed by bar
(?<=) - Positive look behind assertion (?<=foo)bar matches bar when preceded by foo
(?<!) - Negative look behind assertion (?<!foo)bar matches bar when not preceded by foo
(?>) - Once-only subpatterns (?>\d+)bar Performance enhancing when bar not present
(?(x)) - Conditional subpatterns
(?(3)foo|fu)bar - Matches foo if 3rd subpattern has matched, fu if not
(?#) - Comment (?# Pattern does x y or z)
?>
Дополнения от меня
Posix символьные классы
Дополнительные шорткуты для шаблонов. Могут применяться только внутри классов.
Пример для поиска числа с пробелами - preg_match("@[[:space:]\d]+@", $string)
[:alnum:] - буквенно-цифровые символы ([A-Za-z0-9])
[:alpha:] - альфа-символы (символы алфавита) ([A-Za-z]).
[:blank:] - пробел или табуляция
[:digit:] - цифры ([0-9])
[:lower:] - строчные буквы ([a-z])
[:upper:] - прописные буквы ([A-Z])
[:punct:] - знаки пунктуации, исключая пробелы
[:space:] - пробел
?>
Внутренние модификаторы шаблонов
Модификаторы m, s, x, U, X, J могут использоваться внутри шаблона.
Например (?im) установит мультистроковой регистронезивисимый метод поиска для паттерна.
Отключить внутренние модификаторы можно перечислив их через дефис, например (?im-sx)
Пример:
шаблон (?i:foo) совпадет с "FoO"
Именованный "захват"
Возможность регулярных выражений именовать ключи в результирующем массиве совпадений.
Записывается: (?<name>), (?'name') или (?P<name>).
Раньше поддерживался только такой синтаксис: (?P<name>). [<php5.2.2]
<?php
preg_match('/Name: (.+), Age: (\d+)/', $text, $matches);
preg_match('/Name: (?P<Name>.+), Age: (?P<Age>\d+)/', $text, $matches);
?>
Результат скрипта:
array('Name' => 'строка', 'Age' => 'число')
Замена через callback-функцию
В php есть возможность указать функцию обратного вызова
для совпадений, если нам нужно проделать с ними необычные вещи.
Для этого используется preg_replace_callback.
Раcсмотрим пример
<?php
$line = preg_replace_callback(
'|<p>\s*\w|',
create_function(
'$matches',
'return strtoupper($matches[0]);'
),
$line
);
?>
Данный код заменит все первые буквы в параграфах на заглавные.
В php >= 5.3 callback-функцию можно записать в сокращенном виде
<?php
// вместо create_function используем анонимную функцию
$line = preg_replace_callback(
'|<p>\s*\w|',
function ($matches) {
return strtoupper($matches[0]);
},
$line
);
?>
Смотрите также
Логические операции в регулярных выражениях
Боремся с кириллицей и юникодом
Очень полезно и притом все понятно объяснено.
и вот фраза: Совпадает с НОЛем и БОЛЬШЕ вхождений символа, следующего сразу за звездочкой.
чет не работает она... работает если .. следующего сразу ПЕРЕД звездочкой.
Совпадает с НОЛем и БОЛЬШЕ вхождений символа, следующего сразу за звездочкой.
А надо - СТОЯЩЕГО ПЕРЕД звездочкой.
"Дальнейший поиск не продолжается (см. preg_amtch_all)"
preg_match_all
спасибо, ошибку на сайте поправили
Единственное замечание по примеру с фигурными скобками:
замените
echo preg_match("/PHP[0-9]3/", $string, $matches);
на
echo preg_match("/PHP[0-9]{3}/", $string, $matches);
В том варианте что сейчас возвращает 0.
обозначает начало стрAки и доллар
строку за однострочHкую
Поправьте.
2kish
Очень хорошо написано для новиков!)
Александр