preg_match($pattern, $subject, $matches) проверяет, совпадает ли строка с регулярным выражением. Функция возвращает 1 при совпадении и 0 в остальных случаях и заполняет $matches найденным: preg_match('/\d+/', 'Order 4521 shipped', $m) возвращает 1 и записывает в $m[0] значение "4521".
Шаблон это строка с разделителями вокруг, обычно /.../, за которыми идут модификаторы, например i. Пишите шаблоны в одинарных кавычках: внутри двойных PHP сначала раскрывает $name и escape-последовательности вроде \x41 или \101, и движок регулярных выражений может получить не тот шаблон, который вы набрали.
Группы захвата
Круглые скобки в шаблоне захватывают ту часть строки, с которой совпали. $m[0] это всё совпадение, $m[1] первая группа, $m[2] вторая, отсчёт ведётся по открывающим скобкам слева направо.
Именованные группы
(?<name>...) даёт группе имя. Значение хранится и под именем, и под номером, поэтому код, который читает результат, не сломается, если кто-то добавит группу раньше в шаблоне.
Все совпадения через preg_match_all
preg_match_all() продолжает поиск после первого совпадения и возвращает число совпадений. По умолчанию $m[0] содержит все полные совпадения, а $m[1] все значения первой группы. С PREG_SET_ORDER вы получаете по массиву на каждое совпадение, и по нему проще идти циклом.
Проверка ввода: якоря, номера телефонов, почтовые индексы
Для проверки шаблон должен совпадать со всей строкой, поэтому начинайте его с ^ и заканчивайте $. Одна ловушка: $ совпадает и перед последним переносом строки, поэтому '/^\d+$/' принимает "123\n". Добавьте модификатор D или используйте \z, который совпадает только в самом конце.
Регулярное выражение для адресов email либо отклоняет допустимые адреса, либо принимает недопустимые. Вместо него используйте filter_var($email, FILTER_VALIDATE_EMAIL) (смотрите filter_var()).
Модификатор u для UTF-8 и японского текста
Без модификатора u шаблон работает с байтами. Японский символ занимает в UTF-8 три байта, поэтому . совпадает с третью символа, и длины получаются неправильными. С u шаблон работает с символами, и можно использовать классы свойств Unicode.
u ещё и проверяет строку: если она не является корректным UTF-8, preg_match() возвращает false, а не ищет совпадение.
Экранирование пользовательского ввода через preg_quote
Символы вроде ., +, ?, ( и / имеют в шаблоне особый смысл. Если часть шаблона приходит из переменной, например поисковый запрос, пропустите её через preg_quote() с разделителем вторым аргументом, иначе 1+1 совпадёт с 11, а неэкранированный / сломает шаблон.
Неверный шаблон не выбрасывает исключение. PHP печатает предупреждение, а preg_match() возвращает false:
Warning: preg_match(): No ending delimiter '/' found in /path/to/index.php on line 3
Поэтому проверяйте === false (или preg_last_error_msg()), когда шаблон собирается во время выполнения. Для простой проверки подстроки без всякого шаблона str_contains() быстрее и понятнее. Чтобы изменить найденный текст, используйте preg_replace().
Часто задаваемые вопросы
Что возвращает preg_match в PHP?
1, если шаблон совпал, 0, если нет, и false, если сам шаблон неверен. Поскольку 0 и false оба ложны, сравнивайте через === 1, когда нужно отличить сломанный шаблон от отсутствия совпадения.
Как получить найденный текст из preg_match?
Передайте третий аргумент: preg_match('/(\d+)/', 'Order 4521', $m). Тогда $m[0] это всё совпадение, а $m[1] первая группа захвата, здесь обе равны "4521". С именованной группой (?<id>\d+) значение есть и в $m['id'].
Чем preg_match отличается от preg_match_all?
preg_match() останавливается на первом совпадении. preg_match_all() находит все совпадения, возвращает их количество и заполняет $matches всеми: preg_match_all('/\d+/', 'a1 b22 c333', $m) возвращает 3, а $m[0] равно ["1", "22", "333"].
Как использовать preg_match с кириллицей, японским или другим текстом в UTF-8?
Добавьте модификатор u: preg_match('/^.{3}$/u', '日本語') возвращает 1. Без u PHP работает со строкой как с байтами, поэтому . совпадает с одним байтом трёхбайтового символа. С u можно использовать и классы Unicode, например \p{Han}, \p{Hiragana} и \p{Katakana}.
Как проверить, что строка содержит только цифры, в PHP?
preg_match('/^\d+$/D', $s) или без регулярного выражения ctype_digit($s). Модификатор D (или \z вместо $) важен: обычный $ принимает и перенос строки в конце, поэтому "123\n" прошло бы проверку.