Регулярные выражения — программируем текстовый поиск
24.10.08Мой Компьютер, №07 (511), 01.07.2008
При программировании зачастую возникает необходимость выполнять поиск или замену в текстовых данных. Для этого в PHP существуют простые и удобные функции strpos(), substr(), str_replace(). Но они помогают только тогда, когда точно известно, что надо искать. В более сложных ситуациях (к примеру, если надо выделить из URL название страницы — для этого надо найти последний слэш в строке) приходится реализовать заковыристые алгоритмы, что является лишней тратой времени и нервов. Но зачем изобретать велосипед? Ведь для поиска в текстовых данных уже давно существует надежный и мощный инструмент, именуемый регулярными выражениями.
Регулярные выражения — это средство, при помощи которого можно легко найти нужные фрагменты в текстовых данных. В отличие от функции strpos(), которая ищет конкретный текст, они основываются на использовании образцов для поиска. Образец, шаблон, паттерн (англ. pattern) — ключевое понятие в регулярных выражениях. Это некая сущность, которую мы ищем, но представленная не вербально (последний слэш в строке, номер телефона), а при помощи специального языка. На языке регулярных выражений можно представить практически любую текстовую конструкцию. В этом сила данного инструмента. В конце прошлого века регулярные выражения произвели настоящий прорыв в отрасли обработки текстовой информации.
Как и многие полезные вещи, регулярные выражения пришли из операционной системы UNIX. Существует их две разновидности — POSIX-совместимые (были разработаны первыми и сейчас считаются устаревшими) и Perl-совместимые (обладают более богатым синтаксисом, считаются более прогрессивными и сейчас наиболее популярны). Соответственно, последние мы и будем рассматривать.
Шаг 1. Начинаем с азов
Какой самый простейший паттерн? Нетрудно догадаться, что это паттерн, описывающий точно заданную строку символов. То есть паттерн abc найдет строку abc. В регулярных выражениях любой символ означает самого себя. Исключение составляют специальные метасимволы ( ^ $ . [ ] | ( ) ? * + { } -), которые, по сути, являются операторами языка регулярных выражений, а также символы-ограничители (/ или < >) паттерна.
Что же делать, если надо искать один из выше перечисленных символов? На помощь приходит наш старый знакомый слэш. Если его поставить перед метасимволом, то метасимвол теряет свой «служебный статус». Ну, а сам трудяга-слэш изображается в виде самого себя, но удвоенного: . Соответственно, для поиска сроки 1+1 паттерн будет 1+1, для поиска строки array[] — array[] и т.д.
Шаг 2.
Escape-последовательности
![]() |
Табл. 1 |
С алфавитно-цифровыми и служебными символами мы разобрались. Теперь представим ситуацию, когда нам надо найти какой-нибудь непечатный символ — пробел, табуляцию, перенос строки и т.п. Читатели, знакомые с языком C, сразу сообразят, что такие символы изображаются через escape-последовательности. Perl-совместимые регулярные выражения поддерживают следующие последовательности (табл. 1).
Шаг 3. Группы символов и повторения
Итак, мы рассмотрели, как в паттернах задаются конкретные символы и слова. Но, как говорилось, основная сила регулярных выражений в том, что они могут искать некоторую сущность, заданную не определенным текстом, а некоторыми общими характеристиками. Например, мы ищем в тексте номер телефона. Что общего у всех номеров телефона? Формат записи. Каждый номер телефона состоит из кода АТС (3 цифры) и двух двухзначных чисел, разделенных дефисами.
Итак, нам надо найти строку по следующему описанию: вначале идут три цифры, причем первая не ноль; затем тире; потом две цифры, потом опять тире, потом еще две цифры.
Для решения этой задачи нам надо уметь записывать:
-
диапазон значений, который будет стоять на месте одного символа;
-
количество повторений символа.
В Perl-совместимых регулярных выражениях для этого используются специальные метасимволы.
Для выбора из группы символов используются квадратные скобки, в которых и перечисляются возможные значения (без запятых между ними). Например, [abc] означает что символ может принимать значение a, b или c. Если нам надо цифры, то перечень будет следующим: [0123456789]. Наверняка вы скажете, что это слишком громоздкая запись. И будете правы. На самом деле можно записать намного проще, при помощи диапазона: [0-9]. В одной группе можно указывать несколько диапазонов, совмещать диапазоны и обычное перечисление значений: [A-Za-z], [0-9abc]. Какой угодно символ обозначается точкой: . (без квадратных скобок). Существуют также определенные обозначения для указания наиболее часто используемых групп символов (цифры, алфавитно-цифровые и т.д.), а также определенные нюансы в использовании символов – и ], но мы их рассмотрим в следующих статьях.
Для выбора количества повторений используется специальная конструкция метасимволов, именуемая квантификатором (англ. quantity — количество). Квантификатор записывается при помощи фигурных скобок {m,n}, где m — минимальное, а n — максимальное количество повторений символа. Например, запись [0-9]{2,3} означает, что мы ищем последовательность из двух или трех цифр. Верхнюю (но не нижнюю!) границу можно не указывать: [0-9]{2,} будет означать поиск последовательности двух и более цифровых знаков. Если надо найти точное количество символов, то надо указать только одно число без запятой ([0-9]{2} — ровно два цифровых знака).
Для наглядности напишу небольшую табличку квантификаторов (табл. 2).
![]() |
Табл. 2 |
Квантификатор {0,1} применяется для задания в паттерне символа или последовательности, которая может присутствовать, а может и не присутствовать в сущности, которую ищем. К примеру, если мы задаем паттерн для расширенной записи телефона с кодом страны и города, то плюс в начале номера, который может быть или не быть, будет обозначаться как +{0,1}.
ВНИМАНИЕ! КВАНТИФИКАТОРОВ ВИДА «ДО m РАЗ» ({,m}) НЕ СУЩЕСТВУЕТ. КОНСТРУКЦИЯ {,m} (где m — некоторое число) БУДЕТ ВОСПРИНЯТА КАК ОБЫЧНАЯ ПОСЛЕДОВАТЕЛЬНОСТЬ СИМВОЛОВ!
Шаг 4. Конструируем регулярные выражения
Итак, мы уже знаем, как указать в паттерне диапазон значений, которые может принимать один символ и количество его повторений. Этих знаний достаточно, чтобы составлять простейшие паттерны.
Мы имеем некоторую сущность, которую хотим найти. В данном случае это номер телефона. Для того, чтобы записать паттерн в виде последовательности операций перечисления и повторения, мы саму сущность должны разбить на кусочки, в каждом из которых повторяются символы однородной группы (символы из одного диапазона). Удобно это делать, мысленно пробегая слева направо по строке, которую ищем, и выделяя такие однородные группы.
![]() |
Табл. 3 |
К примеру, для номера телефона — сначала идет код АТС, он состоит из трех цифр, первая из которых не нулевая. Тут две группы символов: один символ диапазона 1–9 и последовательность двух символов диапазона 0–9. На языке регулярных выражений это запишется как [1-9]{1}[0-9]{2}. После кода АТС идет дефис, следовательно, дописываем в паттерн обозначение дефиса (не забываем поставить слэш, т.к. это метасимвол): . И так далее. Подробный процесс создания паттерна для номера телефона приведен в таблице 3.
Шаг 5. Реализация на PHP
Итак, мы создали паттерн для поиска телефонного номера. Теперь вам уже, наверное, не терпится опробовать его на практике :-). Не волнуйтесь, сейчас перейдем к практической работе.
Для чего используются регулярные выражения? Да для тех же целей, что и функции strpos(), substr(), str_replace():
-
проверка на соответствие образцу (например, проверка корректности введенного в форму телефона, е-mail и т.п.);
-
извлечение из текста участков, соответствующих образцу (например, извлечь из текста письма клиента его телефон; извлечь из документа-отчета, содержащего отформатированные данные, отдельные поля и т.д.);
-
замена в тексте участков, соответствующих образцу (например, вырезать из текста объявления ссылки, чтобы пользователи не могли рекламировать сайты через доску объявлений).
Для решения вышеуказанных задач, в PHP существуют функции preg_match(), preg_match_all(), preg_replace(). Сегодня мы кратко рассмотрим первые две из них.
Функция preg_match() проверяет, соответствует ли строка образцу, заданному паттерном.
Формат вызова:
mixed preg_match ( string $pattern , string $subject );
Если в строке есть хотя бы один участок, соответствующий паттерну, то функция вернет количество совпадений. Если совпадений нет — вернет 0. Если вы допустили в маске ошибку, на выходе функция выдаст FALSE.
Самые нетерпеливые, наверное, уже написали скрипт, ввели в качестве первого параметра наш паттерн, в качестве второго — любой номер телефона, запустили и… функция выдала ошибку :-). Дело в том, что в PHP паттерны необходимо заключать в специальные ограничители. Обычно для этих целей используются пары символов / / или < >. ВНИМАНИЕ! Если символ-ограничитель используется в паттерне, он должен быть «заслэшен»!
Возможности функции демонстрирует скрипт example1.php. Он проверяет, является ли введенное в поле формы значение номером телефона:
<?php
// если в поле формы был введен текст
if (isset($_REQUEST[«phone»]))
{
// выполняем проверку на соответствие регулярному выражению
if (preg_match(«/[1-9][0-9]{2}-[0-9]{2}-[0-9]{2}/», $_REQUEST[«phone»]))
// в тексте поля формы имеются совпадения с паттерном — следовательно, в нем содержатся
// номера телефонов
$result = «Введенный текст является номером телефона»;
else
// соответствий нет — текст не содержит номера телефонов
$result = «Введенный текст не является номером телефона»;
}
?>
<!—собственно сама HTML-форма —>
<form id=»checkform» name=»checkform» action=»example1.php» method=»post»>
<table width=»250″>
<tr>
<td>
Номер телефона:
</td>
<td>
<!— поле ввода —>
<input type=»text» id=»phone» name=»phone» size=»15″ value=»<?php echo $_REQUEST[«phone»]; ?>»>
</td>
</tr>
<tr>
<td colspan=»2″ align=»center»>
<input type=»submit» value=»Проверить»>
</td>
</tr>
</table>
</form>
<?php
// если в поле формы был введен текст
if (isset($_REQUEST[«phone»]))
{
?>
<br>
<?php
// выводим результат проверки
echo $result;
}
?>
Запускаем скрипт, вводим в поле разные значения и любуемся результатом (рис. 1, 2, 3):
![]() |
![]() |
![]() |
Рис. 1 |
Рис. 2 |
Рис. 3 |
Функция preg_match_all() позволяет извлечь из текста все соответствия паттерном.
Формат вызова:
int preg_match_all ( string $pattern , string $subject , array $&matches);
Функция ищет в строке subject все совпадения с шаблоном pattern и формирует из них массив matches. Формат этого массива может меняться в зависимости от наличия в шаблоне подвыражений (что такое подвыражения, вы узнаете в следующих статьях) и дополнительных параметров, переданных в функцию. Но в простейшем случае нулевой элемент массива matches будет массивом, содержащим все участки текста, которые совпали с паттерном.
Возможности функции демонстрирует скрипт example2.php. Он обрабатывает текст, введенный в область ввода формы, извлекает из него все телефоны и выводит на печать.
<?php
// если в поле формы был введен текст
if (isset($_REQUEST[«text»]))
{
// выполняем проверку на соответствие регулярному выражению
// и извлекаем все совпадения
if (preg_match_all(«/[1-9][0-9]{2}-[0-9]{2}-[0-9]{2}/», $_REQUEST[«text»], $matches))
{
// в тексте поля формы имеются совпадения с паттерном — следовательно, в нем содержатся
// номера телефонов
// нулевой элемент массива $matches содержит все совпадения.
// объединяем его элементы через запятую функцией implode() и добавляем
// к строке результата
$result = «Во введенном тексте содержатся следующие номера телефонов: «.implode(«, «, $matches[0]);
}
else
// соответствий нет — текс не содержит номера телефонов
$result = «Во введенном тексте нет номеров телефона»;
}
?>
<!—собственно сама HTML-форма —>
<form id=»checkform» name=»checkform» action=»example2.php» method=»post»>
<table width=»250″>
<tr>
<td>
Введите текст:
</td>
</tr>
<tr>
<td>
<!— поле ввода —>
<textarea id=»text» name=»text» style=»width:100%;» rows=»5″><?php echo $_REQUEST[«text»]; ?></textarea>
</td>
</tr>
<tr>
<td align=»center»>
<input type=»submit» value=»Проверить»>
</td>
</tr>
</table>
</form>
<?php
// если в поле формы был введен текст
if (isset($_REQUEST[«text»]))
{
?>
<br>
<?php
// выводим результат
echo $result;
}
?>
Запускаем скрипт, открываем страничку контактов какой-нибудь киевской фирмы, копируем ее содержимое, вставляем в поле ввода и любуемся результатом (рис. 4, 5).
![]() |
![]() |
Рис. 4 |
Рис. 5 |
Итоги
Мы познакомились с регулярными выражениями, узнали, что это такое и с чем его едят, рассмотрели простейшие случаи их практического применения. В следующих статьях мы будем знакомиться с другими возможностями этого мощного инструмента. А пока потренируйтесь немного и попробуйте самостоятельно сконструировать и проверить следующие паттерны:
-
шаблон мобильного номера (+380xxyyyyyyy или +38(0xx)yyyyyyy или +38(0xx)yyy yyyy или +38(0xx)yyy-yy-yy);
-
шаблон е-мейла (логин@сервер);
-
шаблон URL (http://www.что-то_там) — «www» может либо быть, либо не быть.
Желаю вам успешно решить задания, и до встречи на страницах МК!
Алексей «CyberAdmin» СЕРДЮКОВ
Web-droid редактор
Не пропустите интересное!
Підписывайтесь на наши каналы и читайте анонсы хай-тек новостей, тестов и обзоров в удобном формате!


Samsung Galaxy A36 и Galaxy A56 — доступные флагманские технологии



У Samsung Galaxy A36 и Galaxy A56 одинаково хорошие дисплеи, емкие аккумуляторы, есть поддержка обновлений софта в течение 6 лет. Расскажем подробнее чем еще они интересны

Samsung представила защищённый смартфон Galaxy XCover 7 Pro и планшет Galaxy Tab Active 5 Pro Samsung защита планшет смартфон
Samsung анонсировала два новых устройства, рассчитанных на работу в сложных условиях – смартфон Galaxy XCover 7 Pro и планшет Galaxy Tab Active 5 Pro
1-дюймовый датчик камеры OmniVision поддерживает запись HDR-видео до 8K камера разработка смартфон
OmniVision представила новый CMOS-сенсор OV50X с разрешением 50 мегапикселей, разработанный специально для использования в флагманских моделях смартфонов