Регулярные выражения в PHP: практические примеры и типичные ошибки
Основное эффективное решение: preg_match_all с захватом данных
Для извлечения всех совпадений с регулярным выражением из строки функция preg_match_all является наиболее универсальной. Она возвращает количество найденных совпадений и заполняет массив $matches всеми совпадениями и подмасками. Это решение подходит для обработки структурированных данных, таких как телефонные номера, email-адреса, ссылки.
$text = "Телефоны: +7 (123) 456-78-90 и +7 (987) 654-32-10";
$pattern = '/\+7\s*\((\d{3})\)\s*(\d{3})-(\d{2})-(\d{2})/';
preg_match_all($pattern, $text, $matches);
print_r($matches);Php маленькие буквы (преобразование строки в нижний регистр в php)
Array
(
[0] => Array
(
[0] => +7 (123) 456-78-90
[1] => +7 (987) 654-32-10
)
[1] => Array
(
[0] => 123
[1] => 987
)
[2] => Array
(
[0] => 456
[1] => 654
)
[3] => Array
(
[0] => 78
[1] => 32
)
[4] => Array
(
[0] => 90
[1] => 10
)
)Character php (символы php)
Пояснение:
Регулярное выражение разбивает номер телефона на код страны, код города и остальные цифры. $matches[0] содержит полные совпадения, $matches[1] - первую группу и так далее.Типичные ошибки: забыть экранировать обратную косую черту в строке PHP (использовать одинарные кавычки или дважды экранировать). Неправильные модификаторы (например, отсутствие модификатора u для UTF-8).
Решение: всегда тестировать выражение в отдельном скрипте; использовать модификатор u, если строка в UTF-8; проверять возвращаемое значение (false при ошибке или 0 при отсутствии совпадений).
Различные варианты использования preg функций
Как найти первое вхождение подстроки по шаблону?
Функция preg_match останавливается после первого совпадения и полезна для проверки наличия шаблона или извлечения первой группы.
$url = "https://example.com/page?var=123";
$pattern = '/https?:\/\/([^\/]+)/';
if (preg_match($pattern, $url, $match)) {
echo $match[1]; // example.com
}
Php new line (символ новой строки в php)
example.com
Php проверить строку (проверить строку в php)
Ошибка: если шаблон не найден, preg_match возвращает 0, а не false. Ложное срабатывание при проверке if(preg_match(...)) в случае ошибки в шаблоне (возвращает false).
Решение: использовать строгое сравнение: if (preg_match($pattern, $subject) === 1).
Как заменить все вхождения шаблона с использованием захваченных групп?
preg_replace выполняет поиск и замену по регулярному выражению. Можно использовать обратные ссылки (\1, $1) в строке замены.
$text = "Цена: 100 руб., скидка 20 руб.";
$pattern = '/(\d+)\s*руб\./';
$replacement = '$1 USD';
echo preg_replace($pattern, $replacement, $text);Php пробел (удаление пробелов в php)
Цена: 100 USD, скидка 20 USD
удалить html теги php (php удалить html теги)
Проблема: обратная ссылка $1 может интерпретироваться как переменная, если строка замены в двойных кавычках. Лучше использовать одинарные кавычки или экранировать.
Ошибка: при использовании модификатора e (устарел) - теперь применяют preg_replace_callback.
Как разбить строку на части по сложному разделителю?
preg_split делит строку по регулярному выражению, в отличие от explode, поддерживает несколько разделителей и необязательную часть.
$data = "apple, orange; banana: cherry";
$parts = preg_split('/[,;:\s]+/', $data);
print_r($parts);удалить пробел в строке php (php удалить пробелы в строке)
Array
(
[0] => apple
[1] => orange
[2] => banana
[3] => cherry
)Php подстроки (получение подстроки в php)
Ошибка: пустые элементы при множественных разделителях в начале или конце строки. Решение: добавить флаг PREG_SPLIT_NO_EMPTY.
При использовании PREG_SPLIT_DELIM_CAPTURE и наличии групп можно получить разделители.
Как отфильтровать массив по шаблону?
preg_grep возвращает элементы массива, соответствующие регулярному выражению. Полезно для поиска записей в логах.
$files = ['image.jpg', 'photo.png', 'document.pdf', 'img.gif'];
$images = preg_grep('/\.(jpg|png|gif)$/i', $files);
print_r($images);Php длина строки (длина строки php)
Array
(
[0] => image.jpg
[1] => photo.png
[3] => img.gif
)Php str replace (замена в строке php)
Ошибка: индексы сохраняются, что может привести к разрыву массива. Решение: использовать array_values для переиндексации.
Флаг PREG_GREP_INVERT возвращает несовпадающие элементы.
Как выполнить сложную замену с обработкой каждого совпадения?
preg_replace_callback позволяет передать пользовательскую функцию для каждого совпадения. Применяется для динамической замены.
$text = "Сегодня 2023-12-25, а завтра 2023-12-26";
$pattern = '/(\d{4})-(\d{2})-(\d{2})/';
$result = preg_replace_callback($pattern, function($m) {
return "$m[3].$m[2].$m[1]";
}, $text);
echo $result;Php без учета регистра (игнорирование регистра в php)
Сегодня 25.12.2023, а завтра 26.12.2023
Ошибка: внутри callback-функции нельзя использовать переменные внешней области без use, иначе они не будут доступны.
Решение: передать переменные через use (&) или использовать статические свойства.
Расширенные примеры регулярных выражений в PHP
Извлечение данных с позициями и именованными подмасками
Именованные группы (?P
$log = "Ошибка: [2024-01-15 14:30:00] код 500 в файле index.php";
$pattern = '/(?P\d{4}-\d{2}-\d{2}) (?P
Array
(
[0] => 2024-01-15
[1] => 12
)
Array
(
[0] => 500
[1] => 46
)
Проблемы: позиции могут сбиваться при многобайтовых кодировках без модификатора u. Решение: добавить u и пересчитывать позиции отдельно.
Разбор вложенных структур (рекурсивные шаблоны)
Рекурсивные шаблоны (?R) позволяют обрабатывать вложенные скобки, теги и т.д.
$text = "(a (b c) d (e (f) g))";
$pattern = '/\((?:[^()]|(?R))*\)/';
preg_match_all($pattern, $text, $matches);
print_r($matches[0]);
Array
(
[0] => (a (b c) d (e (f) g))
[1] => (b c)
[2] => (e (f) g)
[3] => (f)
)
Замечание: рекурсия может быть дорогой, необходимо ограничивать глубину с помощью модификатора (?R) или установки предела pcre.backtrack_limit.
Ошибка: при неправильном балансе скобок шаблон может работать бесконечно. Нужно всегда тестировать на краевых случаях.
Преобразование BBCode в HTML с сохранением состояния
Callback-функция может использовать внешнюю переменную для вложенных тегов.
$text = "[b]Жирный [i]курсив[/i] текст[/b]";
$stack = [];
$result = preg_replace_callback('/\[(\/?)(\w+)\]/', function($m) use (&$stack) {
$tag = $m[2];
$closing = ($m[1] === '/');
if (!$closing) {
$html = '<' . $tag . '>';
array_push($stack, $tag);
} else {
if (end($stack) === $tag) {
array_pop($stack);
$html = '' . $tag . '>';
} else {
$html = $m[0]; // невалидный тег вернуть как есть
}
}
return $html;
}, $text);
echo $result;
Жирный курсив текст
Проблема: если вложенность неправильная, теги разъезжаются. Решение: добавлять проверку стека.
Сложный шаблон с комментариями (модификатор x)
Модификатор x позволяет вставлять пробелы и комментарии (#) в шаблон.
$text = "IP: 192.168.1.1, port: 8080";
$pattern = '/
(\d{1,3}) # первая октет
\. # точка
(\d{1,3}) # вторая
\.
(\d{1,3}) # третья
\.
(\d{1,3}) # четвёртая
/x';
preg_match($pattern, $text, $m);
echo "IP: $m[0]\n";
echo "Октеты: $m[1], $m[2], $m[3], $m[4]";
IP: 192.168.1.1 Октеты: 192, 168, 1, 1
Важно: модификатор x изменяет поведение пробелов - чтобы включить пробел в шаблон, нужно экранировать или использовать \x20.
Группировка совпадений по порядку (PREG_SET_ORDER)
По умолчанию preg_match_all группирует по индексу подмаски. PREG_SET_ORDER создаёт массив, где каждый элемент - набор подмасок одного совпадения.
$text = "a=1 b=2 c=3";
$pattern = '/(\w+)=(\d+)/';
preg_match_all($pattern, $text, $matches, PREG_SET_ORDER);
foreach ($matches as $pair) {
echo "{$pair[1]} => {$pair[2]}\n";
}
a => 1 b => 2 c => 3
Удобно для обработки пар ключ-значение. Без флага пришлось бы перебирать параллельные массивы.