Регулярные выражения в PHP

Регулярные выражения (сокращенно — regex) представляют собой последовательности символов, которые формируют шаблоны поиска. В основном они используются в шаблонах сопоставления со строками.

Краткая история

  • Все началось в 1940 — 1960-х годах, когда множество умных людей говорили о регулярных выражениях;
  • 1970-е годы g / re / p;
  • 1980 Perl и Генри Спенсер;
  • 1997 PCRE (регулярные выражения, совместимые с Perl). Именно тогда начался взлет того, что мы называем регулярные выражения. PCRE предоставляет библиотеки почти для каждого языка.

Общее использование регулярных выражений в PHP

PHP включает в себя три основные функции для работы с PCREpreg_match, preg_match_all и preg_replace.

Сравнение соответствия

Выражение возвращает 1, если соответствие установлено, 0 — если нет, и false — если возникает ошибка:

int preg_match (
    string $pattern,
    string $subject [,
    array &$matches [,
    int $flags = 0 [,
    int $offset = 0
]]])

Регулярного выражения пример, который возвращает количество найденных совпадений:

int preg_match_all (
    string $pattern,
    string $subject [,
    array &$matches [,
    int $flags = PREG_PATTERN_ORDER [,
    int $offset = 0
]]])

Замена

Выражение возвращает замененную строку или массив (на основе объекта $subject):

mixed preg_replace (
    mixed $pattern,
    mixed $replacement,
    mixed $subject [,
    int $limit = -1 [,
    int $count
    ]])

Общее использование регулярных выражений в JavaScript

Регулярные выражения в JavaScript выглядят почти так же, как и в PHP.

Сравнение соответствия

Возвращает массив совпадений или null, если совпадений не найдено:

string.match(RegExp);

Замена

Регулярное выражение, которое возвращает строку с выполненными заменами:

string.replace(RegExp, replacement);

Особенности регулярных выражений в JavaScript

  • Точка никогда не соответствует новой строке:
  • Те же методы для сравнения соответствия и замены через регулярное выражение, что и без них.

Принципы составления шаблонов регулярных выражений

Рассмотрим пример, в котором нужно найти адреса электронной почты в базе кода. Наша цель: /[w.+-]+@[a-z0-9-]+(.[a-z0-9-]+)*/i

Аналоговые сокеты

Регулярные выражения состоят из двух типов символов:

  • специальные символы: []? * + {} () ^ $ /.
  • Литералы.

Представьте себе входные строки как болты, а шаблон — как набор разъемов для них (в соответствующем порядке).

Специальные символы

При проверке регулярных выражений нужно знать, как работают специальные символы:

  • Символ обратной косой черты \ может заменять другой специальный символ в регулярном выражении:
  • Точка и w — .

Совпадение со всеми символами, кроме новых строк. Если хотите проверить на соответствие точке, и только точке — , на соответствие буквам, цифрам и нижнему подчеркиванию — w

  • Квадратные скобки [].

Совпадение с символами внутри скобок. Поддерживает диапазоны. Некоторые примеры:
o [abc] — соответствует любым a, b или c.
o [a-z] прописные буквы.
o [0-9] любая цифра.
o [a-zA-Z] — соответствует любому буквенному символу в нижнем или верхнем регистре.
• Опционально ? Соответствие 0 или 1.
• Звездочка *.

Звездочка обозначает 0 или более символов.

• Плюс +.

Соответствие 1 или более символам.

• Фигурные скобки {}.

Минимальное и максимальное значения. Некоторые примеры синтаксиса регулярных выражений:
o {1,} не менее 1.
o {1,3} от 1 до 3.
o {1,64} от 1 до 64.

Добавим все это, чтобы получить регулярное выражение для адресов электронной почты:

/[w.+-]+@[a-z0-9-]+(.[a-z0-9-]+)*/i

Принципы составления шаблонов регулярных выражений

Как это выглядит в PHP:

preg_match_all(
    "/[w.+-]+@[a-z0-9-]+(.[a-z0-9-]+)*/i",
    $input_lines,
    $output_array
);

Использование регулярного выражения для валидации

Задача: убедиться, что вводимые данные — это то, что мы ожидаем. Цель 1: /[^[]w$.]/ Цель 2: /^[0-9]{1,2}[dwmy]$/

Регулярные выражения подходят для поиска элементов, но вам нужно знать, что именно вы ищете.

Когда не стоит использовать регулярное выражение для проверки?

Многие случаи лучше обрабатывать с помощью функции PHP filter_var. Например, проверка адреса электронной почты должна выполняться с помощью встроенных фильтров PHP:

filter_var(
    'bob@example.com',
    FILTER_VALIDATE_EMAIL
)

Валидация с помощью регулярных выражений

Регулярные выражения в конце строки используют анкоры:

^ — указывает начало строки.
$ — знак доллара, который указывает конец строки.

if (!preg_match("%^[0-9]{1,2}[dwmy]$%", $_POST["subscription_frequency"])) {
    $isError = true;
}

Исключенные классы символов

[^abc] — все, кроме a, b или c, включая новые строки.

Пример, который обеспечивает ввод только буквенно-цифровых символов, тире, точки, подчеркивания:

if (preg_match("/[^0-9a-z-_.]/i", $productCode)) {
    $isError = true;
}

Поиск и замена

Наиболее распространенными функциями PCRE для выполнения поиска и замены являются preg_replace() и preg_replace_callback(). Но есть также preg_filter() и preg_replace_callback_array(), которые делают почти то же самое. Обратите внимание, что функция preg_replace_callback_array() доступна, начиная с PHP7.

Заменить слова в списке

$subject = 'I want to eat some apples.';
echo preg_replace('/apple|banana|orange/', 'fruit', $subject);

Результат

I want to eat some fruits.

Если в регулярном выражении есть подшаблоны (в круглых скобках), можно заменить $N или N (где N является целым числом > = 1), это называется «обратная ссылка».

Перестановка двух чисел

$subject = '7/11';
echo preg_replace('/(d+)/(d+)/', '$2/$1', $subject);

Результат

11/7

Изменение форматирования даты

$subject = '2001-09-11';
echo preg_replace('/(d+)-(d+)-(d+)/', '$3/$2/$1', $subject);

Результат

11/09/2001

Простой пример замены URL-адреса в теге <a>

$subject = 'Please visit https://php.earth/doc for more articles.';
echo preg_replace(
    '#(https?://([^s./]+(?:.[^s./]+)*[^s]*))#i',
    '<a href="$1" target="_blank">$2</a>',
    $subject
);

Результат

Please visit <a href="https://php.earth/doc" target="_blank">php.earth/doc</a> for more articles.

Иногда нужно выполнить сложный поиск и замену, например, при фильтрации/проверке перед заменой. В этой ситуации может пригодиться preg_replace_callback().

Приведенное в предыдущем примере регулярное выражение может заменить только URL-адреса, начинающиеся с http или https. Но теперь нам также нужно заменить URL-адреса, начинающиеся с www. Кто-то подумает, что можно просто изменить https? : // в подшаблоне. Например, на (?: Https? : // | www .), Но это не будет работать в большинстве браузеров, потому что они будут интерпретировать www.domain как относительный путь.

Поэтому в конструкторе регулярных выражений перед заменой нужно выполнить некоторые действия, добавив http://, если URL-адрес начинается с www.

function add_protocol_if_begins_with_www($matches)
{
    $url = strtolower($matches[1]) === 'www.'
        ? 'http://' . $matches[0]
        : $matches[0];
    return "<a href="{$url}">{$matches[2]}</a>";
}
$subject = 'Please visit www.php.earth/doc for more articles.';
echo preg_replace_callback(
    '#(https?://|www.)([^s./]+(?>.[^s./]+)*[^s]*)#i',
    'add_protocol_if_begins_with_www',
    $subject
);

Результат

Please visit <a href="http://www.php.earth/doc" target="_blank">php.earth/doc</a> for more articles.

Проблема: ссылка @mentions и #tags
Цель: /B@([w]{2,})/i

Пожалуйста, оставьте ваши мнения по текущей теме материала. Мы очень благодарим вас за ваши комментарии, отклики, подписки, дизлайки, лайки!

Пожалуйста, оставьте свои мнения по текущей теме статьи. Мы крайне благодарны вам за ваши комментарии, дизлайки, лайки, подписки, отклики!

Вадим Дворниковавтор-переводчик статьи «Regex - regular expressions in PHP»