Регулярные выражения в PHP: практические примеры и типичные ошибки

Раздел: Разработка на 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 первая заглавная (преобразование первой буквы в заглавную в php)
- Php str contains (проверка наличия подстроки в php)
- слова php (слова в php (работа со строками))

Расширенные примеры регулярных выражений в PHP

Извлечение данных с позициями и именованными подмасками

Именованные группы (?P...) делают код читаемее. Флаг PREG_OFFSET_CAPTURE добавляет позицию каждого совпадения.

Пример
$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 = '';
        } 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

Удобно для обработки пар ключ-значение. Без флага пришлось бы перебирать параллельные массивы.

Регулярные выражения в PHP (preg) - comments

En
Php preg (php)