Perl-совместимые регулярные выражения

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

Спецификация PCRE https://www.pcre.org/original/doc/html/pcrepattern.html
Документация от PHP https://www.php.net/manual/ru/reference.pcre.pattern.syntax.php
Функции для работы https://www.php.net/manual/ru/ref.pcre.php

Основные понятия

  • Ограничитель — символ не являющийся буквой, цифрой и обратной косой чертой. Любое регулярное выражение должно быть заключено в ограничители. Обычно для этих целей используют косую черту (слеш). Пример выражения /Привет/;
  • Класс символов — множество букв, цифр и других знаков;
  • Квантификатор — оператор, устанавливающий количество повторений (совпадений) класса символов;
  • Метасимвол — оператор, обозначающий некоторую сущность (начало слова, группу символов, маску и другие);
  • Модификатор — настройка поведения всего выражения;

Классы символов

  • \d — цифра;
  • \D — не цифра;
  • \s — пробельный символ (пробел, табуляция, перенос строки \n, возврат каретки \r);
  • \S — непробельный символ;
  • \w — буква или цифра (используется для поиска слов);
  • \W — не буква и не цифра;
  • \p{XX} и \pXX — символ UTF-8 со свойством XX. Примеры классов:
    \p{L} — буква
    \p{Sc} — денежный знак
    \p{P} — знак пунктуации
    Подробнее https://www.php.net/manual/ru/regexp.reference.unicode.php;
  • \P{XX} и \PXX — символ UTF-8 без свойства XX;

Квантификаторы

По-умолчанию, квантификаторы работают в жадном режиме, захватывая как можно больше символов. Это значит, что в случае совпадения будет выбрано максимально длинное значение. Обратный режим — ленивый, указывает квантификатору захватывать как можно меньше символов.
  • {N} — N повторней. Вместо N указывается целое число;
  • {N1,N2} — N1 или N2 повторений. Где N1 и N2 являются целыми числами;
  • * — 0 и более повторений. Эквивалентен {0,};
  • + — 1 и более повторений; Эквивалентен {1,};
  • ? — 0 или 1 повторение. Эквивалентен {0,1}. Так же этот квантификатор переводит жадные квантификаторы, стоящие перед знаком ?, в ленивые;

Метасимволы

  • . — любой символ, кроме перевода строки;
  • ^ — начало текста (в многострочном режиме – начало строки). Внутри класса символов этот знак используется как оператор отрицания, но только если он указан первым символом класса;
  • $ — конец текста (в многострочном режиме – конец строки);
  • [] — конструкция для обозначения символьного класса;
  • () — конструкция для обозначения подмаски, которые используются для извлечения найденных совпадений;
  • | — условие ИЛИ;
  • \ — обратная косая черта, используется для экранизации служебных символов (метасимволов, квантификаторов);
  • - — минус, используется для указания последовательности символов. Пример задания группы символов, состоящей из заглавных латинских букв A-Z;

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

Ставятся после последнего ограничителя, при этом можно указывать сразу несколько штук. Распространены следующие модификаторы:
  • i — регистронезависимая проверка целевой строки;
  • x — пропуск в шаблоне пробельных символов (включая табы и перевод строки), если они не являются частью символьного класса. Можно использовать однострочные комментарии, начинающиеся с символа #;
  • m — включение режима многострочности. По-умолчанию, система рассматривает текст как одну сплошную строку, даже если в ней есть символы новых строк). Модификатор m включает режим рассмотрения многострочного текста построчно;
  • s — метасимвол . (точка) начинает включать символ перевода строки. Без этого модификатора метасимвол . соответствует всем символам, за исключением перевода строк;
  • u — режим обработки текста в кодировке UTF-8 (актуально при работе с нелатинскими символами);

Документация по модификаторам https://www.php.net/manual/ru/reference.pcre.pattern.modifiers.php

Примеры использования

Поиск слова по тексту
//Исходный текст
$a = '
Прив Приветик Привет Привет2
Hello Привет
Здравствуйте
привет всем
';

//Шаблон поиска слова "Привет". Поиск зависим к регистру
//Для выполнения регистронезависимого поиска нужно добавить модификатор i (получится /Привет/ui)
$b = '/Привет/u';

//Функция выведет количество найденных совпадений подстрок заданному шаблону
//Будет выведено '4'
echo preg_match_all($b, $a);

Выборка дат, указанных в формате ДД.ММ.ГГГГ
//Исходный текст
$a = '
Сегодня, 01.01.2011 наступил Новый год
С 01.января.2011 начнётся новый год.
В период с 01.01.2011 до 09.01.2011 будут праздники, а 23.02..2011 будет 23 февраля.
Не забывайте, что 08.03 наступит 8 марта.
';

/*
В шаблоне указан модификатор x для пропуска, указанных в шаблоне,
пробельных символов и комментариев (начинаются со знака #)
*/
$b = '
/
(				#открытие маски для извлечения значения
	[0-9]{2}	#день
	\.			#.
	\d{2}		#месяц
	\. 			#.
	[1|2|3|4|5|6|7|8|9|0]{4}	#год
)				#закрытие маски для извлечения значения
/x';

//Выполнение поиска
preg_match_all($b, $a, $m);

//Вывод результата
if(isset($m[1]) && count($m[1])>0)
{
	echo '<pre>';
	print_r($m[1]);
	echo '</pre>';
}
else echo 'Ничего не найдено';

/*
Скрипт выведет:
Array
(
    [0] => 01.01.2011
    [1] => 01.01.2011
    [2] => 09.01.2011
)
*/

Получение слов, располагающихся в начале строки и начинающихся с буквы
//Исходный текст
$a = '
Здравствуйте, ребята!
Hello
?? ... хм, а где все?
!Неужели ни кого не осталось и все разбежались по домам?
Нужно-ка позвонить
88000... тишина...
Вот тебе и вечерние покатушки)
';

//В шаблоне указаны три модификатора:
//u - для работы с кириллицей
//m - для включения режима многострочности, при котором символ ^ означает начало строки, а не начало текста
//x - для форматирования шаблона
$b = '
/
^				#начало строки
(				#открытие маски для извлечения значения
	[\p{L}]{1}	#буква
	[\w\-]*		#буква, цифра и минус (тире)
)				#закрытие маски для извлечения значения
/umx';

//Выборка
preg_match_all($b, $a, $m);

//Вывод результата
if(isset($m[1]) && count($m[1])>0)
{
	echo '<pre>';
	print_r($m[1]);
	echo '</pre>';
}
else echo 'Ничего не найдено';

/*
Скрипт выведет:
Array
(
    [0] => Здравствуйте
    [1] => Hello
    [2] => Нужно-ка
    [3] => Вот
)
*/