Освоение регулярных выражений с помощью preg_match
Функция preg_match в PHP: базовые возможности
Основное эффективное решение
Функция preg_match выполняет поиск по регулярному выражению в строке и возвращает количество найденных совпадений (0 или 1, так как поиск останавливается после первого совпадения). В случае ошибки возвращается false.
$subject = 'Привет, мир! PHP 8.3';
$pattern = '/[0-9]+\.[0-9]+/';
if (preg_match($pattern, $subject, $matches)) {
echo 'Версия: ' . $matches[0]; // 8.3
} else {
echo 'Совпадение не найдено';
}
Php только цифры (оставить только цифры в php)
Здесь шаблон ищет числа с точкой (версия PHP). $matches[0] содержит всю найденную подстроку. Если совпадение не найдено, код выполняет ветку else.
Типичные ошибки
- Забывают проверить возвращаемое значение на
false- при синтаксической ошибке в шаблоне preg_match возвращаетfalse, а не 0. Без проверки это может быть воспринято как отсутствие совпадения. - Не экранируют обратные слеши в шаблоне, использующем специальные символы (например,
\d). В двойных кавычках PHP обратный слеш может интерпретироваться, поэтому рекомендуется использовать одинарные кавычки или дополнительное экранирование. - Путают preg_match с preg_match_all - первая возвращает только первое совпадение, вторая - все.
Как проверить, содержит ли строка определённый шаблон?
Простая проверка без извлечения данных: достаточно передать только $subject и $pattern, а аргумент $matches можно опустить.
if (preg_match('/^[A-Z]/', 'Hello')) {
echo 'Строка начинается с заглавной буквы';
}
подстрока строки php (поиск подстроки в строке php)
Проблема
Если не указать модификатор u для Юникода, кириллические заглавные буквы не будут распознаны.
// Неверно для кириллицы:
preg_match('/^[А-Я]/u', 'Привет'); // корректно с u
Php строки в файле (строки в файле php)
Как извлечь первую найденную подстроку с захватом групп?
Функция позволяет захватывать части совпадения с помощью круглых скобок. Результат помещается в массив $matches.
$string = 'Цена: 1500 руб.';
preg_match('/(\d+)\s*руб/', $string, $m);
echo $m[0]; // 1500 руб.
echo $m[1]; // 1500
Php preg match (функция preg_match в php)
Нулевой элемент - полное совпадение, первый элемент - первая захваченная группа.
Типичная ошибка
При указании несуществующего индекса массива возникает предупреждение. Всегда проверяйте наличие совпадений (if (preg_match(...))).
Как получить позицию найденного совпадения?
Флаг PREG_OFFSET_CAPTURE заставляет $matches содержать не только строку, но и её позицию (в байтах или символах в зависимости от модификатора).
$text = 'Код 123, цена 456';
preg_match('/\d+/', $text, $m, PREG_OFFSET_CAPTURE);
print_r($m[0]); // Array ( [0] => 123 [1] => 4 )
убрать теги php (удаление html-тегов в php)
$m[0][0] - найденное значение, $m[0][1] - позиция в строке (начиная с 0).
Проблема
Если в шаблоне есть захватывающие группы, каждая группа также преобразуется в массив с позицией. Это может быть неожиданно для тех, кто привык к обычному виду $matches.
Как использовать именованные группы для удобства?
Именованные группы задаются синтаксисом (?P<name>...) или (?<name>...) (с PHP 7.2). Доступ к ним - по имени ключа.
$date = '2025-03-21';
preg_match('/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})/', $date, $m);
echo $m['year']; // 2025
echo $m['month']; // 03
Php убрать из строки (удаление подстроки в php)
Типичная ошибка
Путаница с синтаксисом: ?P<name> - регистр имеет значение. Кроме того, имена групп должны быть уникальными в шаблоне.
Как обрабатывать кириллицу и Unicode?
Модификатор u включает Юникод-режим. Без него шаблон работает с байтами, и кириллица может не совпадать.
$text = 'Москва - столица';
preg_match('/[а-я]+/u', $text, $m);
echo $m[0]; // Москва (без u вернуло бы пусто или байты)
Проблема
Без модификатора u классы символов вроде \w не включают кириллицу, а квантификаторы могут неправильно работать с многобайтовыми символами. Всегда добавляйте u для текстов на русском.
Как отличить ошибку регулярного выражения от отсутствия совпадения?
При ошибке (например, неверный шаблон) preg_match возвращает false. Для детализации используется preg_last_error().
$result = @preg_match('/[a-z/', 'test'); // ошибка: незакрытый класс
if ($result === false) {
$error = preg_last_error();
if ($error === PREG_INTERNAL_ERROR) {
echo 'Внутренняя ошибка';
} elseif ($error === PREG_BACKTRACK_LIMIT_ERROR) {
echo 'Превышен лимит backtrack';
} else {
echo 'Код ошибки: ' . $error;
}
}
Типичная ошибка
Использование оператора @ для подавления ошибок - временное решение. Лучше проверять шаблон заранее или обрабатывать исключение.
Как выполнить поиск без учёта регистра?
Модификатор i - игнорирование регистра.
$email = 'User@Example.COM';
if (preg_match('/^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i', $email)) {
echo 'Email валиден';
}
Проблема
Без модификатора i потребовалось бы указывать оба регистра в квадратных скобках, что усложняет шаблон.
Расширенные примеры использования preg_match
Ниже приведены нетривиальные сценарии, демонстрирующие продвинутые возможности функции.
Извлечение данных с помощью PREG_OFFSET_CAPTURE для нескольких групп
$log = 'Ошибка в 10:23:45 на строке 42';
$pattern = '/(\d{2}):(\d{2}):(\d{2})/';
preg_match($pattern, $log, $m, PREG_OFFSET_CAPTURE);
echo 'Время: ' . $m[0][0] . ' (позиция ' . $m[0][1] . ')' . "\n";
echo 'Часы: ' . $m[1][0] . ' (поз. ' . $m[1][1] . ')' . "\n";
echo 'Минуты: ' . $m[2][0] . ' (поз. ' . $m[2][1] . ')' . "\n";
echo 'Секунды: ' . $m[3][0] . ' (поз. ' . $m[3][1] . ')' . "\n";
Время: 10:23:45 (позиция 8) Часы: 10 (поз. 8) Минуты: 23 (поз. 11) Секунды: 45 (поз. 14)
Каждая группа возвращается как массив. Позиции указаны в байтах (по умолчанию) или символах с модификатором u.
Именованные группы с модификатором u для кириллицы
$message = 'Сотрудник: Иванов Иван, отдел: Продажи';
$pattern = '/Сотрудник:\s*(?P<name>[А-Яа-я\s]+),\s*отдел:\s*(?P<department>[А-Яа-я]+)/u';
preg_match($pattern, $message, $m);
echo 'Имя: ' . $m['name'] . "\n";
echo 'Отдел: ' . $m['department'] . "\n";
Имя: Иванов Иван Отдел: Продажи
Именованные группы упрощают чтение кода, особенно при большом количестве захватываемых элементов.
Применение PREG_UNMATCHED_AS_NULL для корректной обработки необязательных групп
Флаг PREG_UNMATCHED_AS_NULL (PHP 7.2+) делает незахваченные группы равными null вместо пустой строки. Это удобно при работе с необязательными частями шаблона.
$url = 'https://example.com/path?q=1';
$pattern = '/(https?:)?\/\/([^\/]+)(\/[^?]+)?(\?.*)?/';
preg_match($pattern, $url, $m, PREG_UNMATCHED_AS_NULL);
var_dump($m[3]); // string(5) "/path"
var_dump($m[4]); // string(5) "?q=1"
$url2 = 'http://site.com';
preg_match($pattern, $url2, $m2, PREG_UNMATCHED_AS_NULL);
var_dump($m2[3]); // NULL
var_dump($m2[4]); // NULL
string(5) "/path" string(5) "?q=1" NULL NULL
Без этого флага $m[3] было бы пустой строкой "", что могло бы ввести в заблуждение.
Рекурсивные шаблоны для парсинга вложенных структур (например, скобок)
$code = 'f(g(x), h(y(z)))';
$pattern = '/\(([^()]|(?R))*\)/';
preg_match($pattern, $code, $m);
echo $m[0]; // (g(x), h(y(z)))
(g(x), h(y(z)))
Здесь (?R) - рекурсия всего шаблона. Это позволяет захватывать вложенные скобки. Однако такой шаблон может быть медленным и требовать больших лимитов backtrack.
Использование PREG_OFFSET_CAPTURE совместно с именованными группами
$html = 'Контент';
$pattern = '//';
preg_match($pattern, $html, $m, PREG_OFFSET_CAPTURE);
echo 'ID элемента: ' . $m['id'][0] . ' на позиции ' . $m['id'][1];
ID элемента: main на позиции 9
Комбинация модификаторов s, m, x
Пример
$multi = "Строка 1\nСтрока 2";
// Режим многострочности m: ^ и $ работают для каждой строки
$pattern = '/^Строка\s+\d$/m';
preg_match($pattern, $multi, $m);
echo $m[0]; // Строка 2
// Режим s: точка включает перенос строки
$pattern2 = '/Строка.+2/s';
preg_match($pattern2, $multi, $m2);
echo $m2[0]; // Строка 1\nСтрока 2
// Режим x: игнорирование пробелов в шаблоне (для читаемости)
$pattern3 = '/^Строка \s+ \d $/mx';
preg_match($pattern3, $multi, $m3);
echo $m3[0]; // Строка 2
Строка 2
Строка 1
Строка 2
Строка 2
Строка 1
Строка 2
Строка 2
Модификаторы можно комбинировать: imsu - регистронезависимый, многострочный, точка включает перенос, Юникод.
Обработка больших строк и лимиты backtrack
Пример
$bigString = str_repeat('a', 100000) . 'b';
$pattern = '/(a+)+b/';
$result = preg_match($pattern, $bigString);
if ($result === false) {
$err = preg_last_error();
if ($err === PREG_BACKTRACK_LIMIT_ERROR) {
echo 'Превышен лимит backtrack. Увеличьте pcre.backtrack_limit в php.ini.';
}
}
Превышен лимит backtrack. Увеличьте pcre.backtrack_limit в php.ini.
Шаблоны с вложенными квантификаторами (как (a+)+) могут вызвать катастрофический backtrack. Решение - упростить шаблон или увеличить лимит.
Сравнение preg_match с preg_match_all для извлечения всех совпадений
Пример
$csv = 'item1, item2, item3';
// только первое
preg_match('/item\d+/', $csv, $m);
echo 'preg_match: ' . $m[0] . "\n";
// все
preg_match_all('/item\d+/', $csv, $all);
print_r($all[0]);
preg_match: item1
Array
(
[0] => item1
[1] => item2
[2] => item3
)
Для получения всех совпадений используйте preg_match_all.
Функция preg_match в PHP - comments
EnPhp preg match (php)