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


Оглавление (нажмите, чтобы открыть):

Популярные примеры работы регулярных выражений в PHP

Вопросов по данной теме уйма. И я решил создать свою подборку регулярных выражений. Думаю многим поможет!

Для справки.
. — (точка) соответствует любому символу.
<> — (фигурные скобки) нужны для обозначения количества необходимых символов. Например, w <3>— три буквы w подряд. Также есть диапозон z<2,5>, то есть z может повторяться от 2 до 5 раз.
| — (вертикальная черта) логическое или в регулярных выражениях.
\n — перевод строки
\r — так же перевод строки
\t — табуляция
\d — цифра
\D — только не цифра
\s — пробел
\S — только не пробел
\w — все буквы, цифры и знак подчеркивания «_»
\W — только не буква, цифра или подчеркивание
Модификаторы в конце выражения
/i — делает поиск по выражению регистронезависимым. Нет разницы между заглавным и прописным символом
/U — модификатор указывает на то, что результатом поиска должен быть самый короткий отрывок, удовлетворяющий маске поиска. Рекомендую всегда использовать данный модификатор
/m — этот модификатор позволяет искать отрезок текста только внутри одной строки
/s — поиск идёт всему тексту, не обращая внимания на переносы строк
/x — игнорируются пробельные символы, в том числе символы табуляции и перевода строки

Примеры preg_replace PHP

1. Удаляем определённую ссылку в переменной text

2. Удаляем комментарии в переменной text

3. Удаляем спецсимволы

4. Удаляем всё, что между

5. Удаляем всё, что между

6. Удаляем конкретные символы из строки

7. Удаляем пробелы по бокам строки и обычные пробелы

8. Удаляем лишние переводы строк и переносы

9. Удаляем расширения в названиях файлов

10. Создаём функцию обработки текста

11. Найти содержимое определённого тега и вставить его в другие теги

12. Удаляем многократно повторяющиеся знаки препинания (например, . или . )

13. Добавить или убрать текст в начале или конце переменной с текстом

14. Находим все https:// и заменяем на ссылки

15. Удаление GET-параметров из URL

16. Добавить тег br в начало или конец строк

17. Как конвертировать html в текст

18. Как разобрать email и сделать ссылку

Примеры preg_match PHP

1. проверка mail адреса на корректность

2. Найти mail адреса в тексте

3. Является ли переменная числом, длиной от 13 до 16 символов (проверка кредитной карты)

4. Проверка имени файла

Программы (exe, xpi, . )

Изображения (jpg, png, . )

5. Ищем в тексте мобильные телефоны РФ

6. Состоит ли строка только из букв, цифр и _, длиной от 8 до 20 символов:

7. Есть ли в строке идущие подряд символы, не менее 3-х символов подряд (типа абвгДДДеё, но не ааббаабб):

8. Поиск в разных частях строки конструкции:

9. Проверки на тип браузера. Возвращает true если browser = Netscape 2, 3 or MSIE 3.

Примеры ereg PHP

1. Проверка mail адреса в тексте

Часть 1. Язык Perl — король регулярных выражений

Серия контента:

Этот контент является частью # из серии # статей: Использование регулярных выражений в PHP

Этот контент является частью серии: Использование регулярных выражений в PHP

Следите за выходом новых статей этой серии.

Все устройства получают входную информацию, выполняют какие-либо операции и выдают результат. Например, телефон во время разговора преобразует звуковую энергию в электрический сигнал и обратно. Двигатель потребляет топливо (пар, расщепление атомных ядер, бензин, мышечные усилия) и преобразует его в энергию. Блендер поглощает ром, лед, лайм и кюрасао и взбалтывает их в коктейль Mai Tai. (Или, если вам хочется чего-то изысканного, сделайте Bellini из шампанского и грушевого сока. Блендер – замечательное универсальное устройство.)

Так как программное обеспечение преобразует данные, то каждое приложение фактически является устройством (хоть и виртуальным, так как у него нет физических составляющих). Например, компилятор в качестве входной информации получает исходную программу и преобразует ее в двоичный исполняемый код. Программа прогнозирования погоды генерирует предсказания на основе результатов прошлых (исторических) замеров, а графический редактор обрабатывает пикселы, применяя правила к отдельным пикселам или их группам, чтобы, например, сделать изображение более четким или изменить его стиль.

Так же, как и любое другое устройство, программное обеспечение предназначено для работы с определенным исходным материалом, например, набором чисел, данными XML-схемы или протоколом. Если программе задать некорректную входную информацию — неподходящую по форме или типу, то существует большая вероятность того, что результат будет непредсказуемым и, возможно, даже катастрофическим. Как говорится: «Мусор заложишь — мусор получишь».

На самом деле для решения всех нетривиальных задач необходимо отделять правильные данные от некорректных и отклонять некорректные данные во избежание ошибок в результатах. Это, конечно же, актуально и для Web-приложений, написанных на языке PHP. Неважно, получены ли входные данные из формы для ввода с клавиатуры или в результате выполнения программного запроса Asynchronous JavaScript + XML (Ajax), прежде чем начать какие-либо вычисления, программа должна проверить входную информацию. Возможно, что числовые значения должны находиться в пределах определенного диапазона чисел или представлять собой только целые числа. Возможно, значение должно соответствовать определенному формату, например, почтового индекса. Например, почтовый индекс в США представляет собой пять цифр плюс дополнительный префикс «Plus 4», состоящий из дефиса и 4 дополнительных цифр. Возможно, другие строки также должны состоять из определенного количества символов, например, две буквы для указания аббревиатуры штата США. Строковые данные доставляют особенно много проблем: PHP-приложение должно быть начеку по отношению к злонамеренным программам-агентам, вложенным в SQL-запросы, код JavaScript или любой другой код, которые способны изменить поведение приложения или обойти защиту.

Однако каким образом программа может определить, являются ли входные данные числом или соответствуют ли определенным требованиям, например, к почтовому индексу? На самом деле для реализации проверки путем сопоставления с шаблоном необходим небольшой парсер, создающий конечный автомат, считывающий входные данные, обрабатывающий маркеры, отслеживающий состояние и выдающий результаты. Однако создание и обслуживание даже самого простого парсера может оказаться непростым делом.

К счастью, анализ на основе сопоставления с шаблоном настолько широко распространен в компьютерных технологиях, что с течением времени (примерно с момента появления UNIX®) были разработаны специальные технологии и, конечно же, механизмы обработки, чтобы облегчить рутинную работу. Регулярное выражение (regex) описывает шаблоны посредством лаконичных и удобочитаемых обозначений. Получив регулярное выражение и данные, механизм regex сообщает, совпадают ли эти данные с шаблоном, и если совпадение было обнаружено, что именно совпало.

Вот небольшой пример использования регулярного выражения, взятый из UNIX-утилиты, работающей в режиме командной строки, которая ищет заданный шаблон в содержимом одного или нескольких текстовых файлов UNIX. Команда grep -i -E ‘^Bat’ ищет последовательность символов beginning-of-line (начало строки), обозначаемое «крышкой», [^]), за которым следуют буквы b, a, и t верхнего или нижнего регистра (ключ -i указывает на то, что при сопоставлении с шаблоном регистр не учитывается, таким образом, например, B и b — тождественны). Следовательно, для файла heroes.txt:

Листинг 1. heroes.txt

Вышеупомянутая команда grep выдаст два совпадения:

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

PHP предлагает два программных интерфейса регулярных выражений: один — для интерфейса переносимых операционных систем (POSIX), а второй — для регулярных выражений, совместимых с языком Perl (PCRE). В общем и целом второй интерфейс является более предпочтительным, так как PCRE сам по себе мощнее, чем POSIX, и предоставляет все операторы, используемые в языке Perl. Более подробная информация по обращению к regex-функциям POSIX представлена в документации по языку PHP (см. раздел Ресурсы). В данной статье мы сосредоточим свое внимание на свойствах PCRE.

Регулярные выражения PHP PCRE содержат операторы, позволяющие путем сопоставления находить конкретные символы или другие операторы, определенные местоположения, например, начало и конец строки, начало или конец слова. Регулярные выражения также позволяют описывать альтернативы, которые можно задать альтернативы типа «или»-«или»; повторения фиксированной, изменяемой или неопределенной длины; наборы символов (например, «любая буква от a до m«); и классы, или типы символов (печатаемые символы, знаки препинания). Специальные операторы также разрешают использовать группировку — возможность применить оператор к целой группе других операторов.

В таблице 1 показаны некоторые типичные операторы регулярных выражений. Для создания сложных выражений можно последовательно объединять элементарные операторы из таблицы 1 (и другие).

Таблица 1. Типичные операторы регулярных выражений
Оператор Значение
. (точка) Любой одиночный символ
^ (крышка) Пустая последовательность в начале строки или цепочки
$ (знак доллара) Пустая последовательность в конце строки
A Буква A верхнего регистра
a Буква a нижнего регистра
\d Любая цифра
\D Любой нецифровой символ
\w Любая буква или цифра; синоним — [:alnum:]
[A-E] Любая заглавная буква из A, B, C, D или E
[^A-E] Любой символ, за исключением заглавных букв A, B, C, D или E
X? Найти совпадение по отсутствию или наличию одной заглавной буквы X
X* Ни одной или любое количество заглавных букв X
X+ Одна или несколько заглавных букв X
X

Ровно n заглавных букв X
X

Не менее n и не более m заглавных букв X; если опустить m, то выражение будет искать не менее n заглавных букв X
(abc|def)+ По меньшей мере одно вхождение последовательности abc и def

В следующем примере показано типичное использование регулярного выражения. Например, для web-сайта необходимо, чтобы каждый пользователь регистрировался. Имя пользователя должно начинаться с буквы и содержать от 3 до 10 буквенно-цифровых символов. Для проверки имени пользователя на соответствие ограничениям при отправке данных в приложение можно использовать следующее регулярное выражение: ^[A-Za-z][A-Za-z0-9_]<2,9>$ .

Знак «крышка» соответствует началу строки. Первый набор [A-Za-z] соответствует любой букве. Второй набор [A-Za-z0-9_] <2,9>соответствует последовательности, содержащей от 2 до 9 букв, цифр или символов подчеркивания. Знак доллара ( $ ) соответствует концу строки.

На первый взгляд, знак доллара может показаться лишним, однако его использование важно. Если его пропустить, то условиям данного регулярного выражения будет отвечать любая строка, которая начинается с буквы, содержит от 2 до 9 буквенно-цифровых символов и любое количество других символов. Иными словами, если бы не было знака доллара как привязки к концу строки, то подошла бы недопустимо длинная строка с подходящим началом, например, «martin1234-cruft» .

Программирование на языке PHP и регулярные выражения

В PHP есть функции для поиска совпадений в тексте, замены каждого совпадения на другой текст (похоже на операцию «найти и заменить») и поиска совпадений среди элементов списка. Вот эти функции:

  • preg_match()
  • preg_match_all()
  • preg_replace()
  • preg_replace_callback()
  • preg_grep()
  • preg_split()
  • preg_last_error()
  • preg_quote()

Чтобы показать, как работают эти функции, давайте создадим небольшое PHP-приложение, которое будет просматривать список слов на соответствие определенному шаблону. Слова и регулярные выражения будут вводиться из обычной web-формы, а результаты отображаться в браузере посредством функции simple print_r() . Эта программка пригодится, если возникнет желание проверить или отладить регулярное выражение.

PHP-код показан в листинге 2. Все входные данные берутся из обычной HTML-формы. (Для краткости эту форму и PHP-код, отслеживающий ошибки, опустим.)

Листинг 2. Сравнение текста с шаблоном

Вначале с помощью функции preg_split() строка из слов, разделенных запятыми, преобразуется в отдельные элементы. Данная функция разбивает строку в тех местах, которые соответствуют условиям регулярного выражения. В данном случае регулярное выражение представляет собой просто «,» , (запятая — разделитель списка слов, указанных через запятую). Слэш в начале и в конце просто показывает начало и конец regex.

Третий и четвертый аргументы функции preg_split() необязательны, но полезны. Добавьте в третий аргумент число n целого типа, если необходимо вернуть только первые n совпадений, или -1 , если необходимо вернуть все совпадения. Если в качестве четвертого аргумента задать идентификатор PREG_SPLIT_NO_EMPTY , то функция preg_split() не будет возвращать пустые результаты.

Затем каждый элемент списка слов, разделенных запятыми, корректируется (убираются начальные и конечные пробелы) с помощью функции trim() и сравнивается с заданным регулярным выражением. Функция preg_grep() существенно упрощает процесс обработки списка: просто укажите в качестве первого аргумента шаблон, а в качестве второго — массив слов для сравнения. Функция возвращает массив совпадений.

Например, если в качестве шаблона задать регулярное выражение ^[A-Za-z][A-Za-z0-9_]<2,9>$ и список слов разной длины, то можно получить результат, показанный в листинге 3.

Листинг 3. Результат работы простого регулярного выражения

Кстати, с помощью дополнительного маркера PREG_GREP_INVERT можно инвертировать операцию preg_grep() и найти элементы, которые не совпадают с шаблоном (аналогично оператору grep -v в командной строке). Заменяя 22 строку на $matches = preg_grep( «/$<_REQUEST[ 'regex' ]>/», $words, PREG_GREP_INVERT ) и используя входные данные из листинга 3, мы получим Array ( [1] => 1happy [2] => hermanmunster ) .

Разбор строк

Функции preg_split() и preg_grep() очень удобны. Первая из них может разбирать строку на подстроки, если подстроки разделяются определенным шаблоном. Функция preg_grep() позволяет быстро отфильтровать список.

Но что произойдет, если строку нужно разобрать на составные части, используя одно или несколько сложных правил? Например, в США номера телефонов обычно выглядят следующим образом: «(305) 555-1212,» «305-555-1212,» или «305.555.1212.» Если убрать пунктуацию, то количество символов сократится до 10 цифр, что легко можно определить с помощью регулярного выражения \d <10>. Однако код и префикс (каждый из которых состоит из трех цифр) телефонного номера США не могут начинаться с нуля или единицы (так как нуль и единица используются как префиксы для междугородных звонков). Вместо того чтобы разбивать числовую последовательность на отдельные цифры и создавать сложный код, для верификации можно использовать регулярное выражение.

Фрагмент кода позволяющий решить эту задачу, показан в листинге 4.

Листинг 4. Проверка американского телефонного номера

Давайте пройдем по этому коду:

  • Как показано в таблице 1, в регулярных выражениях используется ограниченный набор специальных символов, например, квадратные скобки ( [ ] ) для наименования последовательности. Если надо найти такой символ в тексте, необходимо «выделить» специальный символ в регулярном выражении, поставив перед ним обратный слэш ( \ ). Когда символ выделен, можно задать его посик, как и любого другого символа. Если нужно найти символ точки, например, в полном составном имени хоста, то напишите \. . При желании строку можно подать в функцию preg_quote() которая выполняет автоматическую изоляцию всех специальных символов регулярных выражений, как показано в строке 1. Если поставить echo() $punctuation после первой строки, то вы должны увидеть \(\)\.- .
  • В строке 2 из телефонного номера убираются все знаки пунктуации. Функция preg_replace() заменяет все символы из $punctuation — операторы из набора [ ] — пустой строкой, эффективно устраняя такие символы. Возвращаемая новая строка присваивается переменной $number .
  • В строке 4 определен шаблон верифицируемого телефонного номера США.
  • Строка 5 реализует сопоставление, сравнивая телефонный номер, который теперь состоит только из цифр, с шаблоном. Функция preg_match() возвращает 1, если есть совпадение. Если совпадения нет, функция preg_match() возвращает нулевое значение. Если во время обработки возникла ошибка, то функция возвращает значение False (ложно). Таким образом, чтобы проверить удачное завершение, необходимо посмотреть, было ли возвращено значение 1. В противном случае проверьте итоговое значение функции preg_last_error() (если используется PHP версии 5.2.0 или выше). Если оно не равно нулю, то, возможно, был превышен лимит вычислений, например, разрешенная глубина рекурсии регулярного выражения. Обсуждение констант и ограничений, применяемых в регулярных выражениях PHP, представлено на странице, посвященной функциям регулярных выражений PCRE (см. раздел Ресурсы).

Извлечение данных

Во многих случаях необходимо только получить ответ на вопрос: «Соответствуют ли данные шаблону?» – например, при проверке данных. Однако чаще регулярные выражения используются для подтверждения соответствия и получения информации о совпадении.

Вернемся к примеру с телефонным номером. Пусть при соответствии шаблону нам необходимо сохранить код, префикс и номер линии в отдельных полях базы данных. Регулярные выражения могут запоминать совпадающие с шаблоном данные с помощью оператора capture . Оператор capture обозначается круглыми скобками и может использоваться в любой части регулярного выражения. Операции capture можно делать вложенными для поиска подсегментов в извлеченных сегментах данных. Например, чтобы из 10-значного номера телефона извлечь код города, префикс и номер линии, можно использовать следующую строку:

Если входные данные соответствуют шаблону, первые три цифры захватываются первой парой круглых скобок, следующие три цифры — второй парой, а последние 4 цифры — последним оператором. Модификация вызова функции preg_match() возвращает извлеченные данные.

Листинг 5. Возврат извлеченных данных функцией preg_match()

Если в качестве третьего аргумента функции preg_match() указать переменную, например, в нашем коде, $matches , то в качестве ее значения будет выступать список извлеченных результатов. Нулевой элемент списка (с индексом 0 ) — это все совпадение целиком; первый элемент — совпадение, относящееся к первой паре круглых скобок, и так далее.

Вложенные операторы capture извлекают сегменты и подсегменты фактически любой глубины. Сложность с вложенными операторами capture состоит в том, чтобы определить, в какой части массива соответствий находится каждое соответствие, например, $matches . Действует следующее правило: подсчитайте порядковый номер открывающей скобки в регулярном выражении — этот номер и будет индексом нужного совпадения в массиве соответствий.

В листинге 6 показан пример (немного надуманный) извлечения частей городского адреса.

Листинг 6. Код для извлечения городского адреса

Опять все совпадение целиком хранится по индексу 0 . А где хранится номер улицы? Если считать слева направо, номер улицы проверяется \d+ . Это вторая открывающая круглая скобка слева, следовательно, значением $matches[2] будет 123 . В $matches[4] оказывается название города, а в $matches[6] — почтовый индекс.

Продвинутые технологии

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

  • Функция preg_replace() может работать как с одной строкой, так и с массивом строк. Если вызвать preg_replace() для массива строк, замена будет выполнена во всех элементах массива. В этом случае код preg_replace() возвращает массив измененных строк.
  • Как и во всех остальных реализациях PCRE, здесь для осуществления замены можно прибегать к сравнению с вложенным шаблоном. Для наглядности давайте рассмотрим проблему стандартизации формата телефонного номера. Заменим все знаки пунктуации точками. Наше решение показано в листинге 7.
Листинг 7. Замена знаков пунктуации точками

Сопоставление с шаблоном и, в случае совпадения, перевод в стандартный телефонный номер выполняется за один шаг.

Выражайтесь!

PHP-приложения применяются для обработки все больших объемов информации. Если необходимо верифицировать входную информацию или разложить данные на части, пользуйтесь регулярными выражениями.

Ресурсы для скачивания

Похожие темы

  • Оригинал статьи: «Mastering regular expressions in PHP, Part 1: Perl may be regex king, but PHP can slice and dice input quickly, too» (EN).
  • Познакомьтесь со статьей Функции регулярных выражений PCRE на PHP.net (EN).
  • PHP.net — ведущий ресурс для PHP-разработчиков (EN).
  • Познакомьтесь с «Рекомендательным списком литературы по PHP» (EN).
  • Повысьте свою квалификацию в области разработок на PHP с помощью раздела Ресурсы с PHP-проектами на developerWorks (EN).
  • Интересные интервью и обсуждения для разработчиков ПО представлены в разделе Подкасты на сайте developerWorks (EN).
  • Работаете с базами данных и PHP? Обратите внимание на Zend Core для IBM — интегрированную, не требующую настройки, легко устанавливаемую среду для разработки и исполнения ПО на PHP, поддерживающую IBM DB2 V9 .
  • В разделе Open source на developerWorks можно найти исчерпывающую практическую информацию, инструментальные средства и новости проектов, которые помогут вам в разработке технологий с открытым исходным кодом и их использовании с другими продуктами IBM (EN).
  • Внесите инновации в свой следующий проект по разработке ПО с открытым исходным кодом с помощью пробной версии программного обеспечения IBM, которые можно скачать или заказать на DVD-диске (EN).
  • Загрузите демо-версии продукта IBM и воспользуйтесь средствами разработки приложений и связующим ПО DB2®, Lotus®, Rational®, Tivoli®и WebSphere® (EN).

Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

ez code

Просто о сложном.

Несколько полезных регулярных выражений для веб-разработки.

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

Введение в регулярные выражения

При первом знакомстве с регулярными выражениями может показаться, что их сложно понять и применять. На самом деле все проще, чем кажется. Перед тем как приступить к рассмотрению сложных примеров, разберем основы:

Регулярное выражение Подходящая строка
foo Строка “foo”
^foo “foo” в начале строки
foo$ “foo” в конце строки
^foo$ Только “foo” в строке
[abc] a, b, или c
[a-z] Любая строчная буква
[^A-Z] Любая не заглавная буква
(gif|jpg) “gif” или “jpeg”
[a-z]+ Одна или более строчных букв
[0-9.-] Любое число, точка, или знак минуса
^[a-zA-Z0-9_]<1,>$ Любое слово длинной не менее 1 буквы, число или _
([wx])([yz]) wy, wz, xy, или xz
[^A-Za-z0-9] Любой символ (не цифра, и не буква)
([A-Z]<3>|[0-9]<4>) Три буквы или 4 цифры

Функции для работы с регулярными выражениями в PHP

Функция Описание
preg_match() Ищет совпадения с шаблоном в заданной строке. Возвращает количество совпадений.
preg_match_all() Ищет все совпадения с шаблоном в строе и помещает их в массив.
preg_replace() Выполняет поиск совпадений с шаблоном в строке и заменяет их.
preg_split() Разбивает строку по регулярному выражению.
preg_grep() Возвращает массив, состоящий из элементов входящего массива, которые соответствуют заданному шаблону.
preg_quote() Добавляет обратный слэш перед каждым служебным символом.

Проверка домена

Проверка на правильное доменное имя.

Подсветка слов в тексте

Очень полезное регулярное выражение для нахождения слов в тексте и их подсветки. Пригодится для поиска.

Подсветка результатов поиска в WordPress

Как уже было сказано, предыдущий пример очень полезен при показе результатов поиска. Применим его к WordPress. Откройте файл search.php, найдите функцию the_title(). Замените её следующим:

Теперь, перед этой строкой вставьте код:

Откройте файл style.css. Добавьте в него строку:

Получить все изображения из HTML документа

Если вам когда-нибудь понадобиться найти все изображения на HTML странице, вам пригодится следующий код. С его помощью можно легко создать загрузчик изображений, используя cURL.

Удаление повторяющихся слов (не зависимо от регистра)

Удаление повторяющихся знаков препинания

Похоже на предыдущее, только удаляет знаки препинания.

Нахождение XML/HTML тега

Простая функция, которая принимает два аргумента: тег, который необходимо найти, и строка, содержащая XML или HTML.

Нахождение XML/HTML тега с определенным значением атрибута

Функция похожа на предыдущую, но появляется возможность указать атрибут тега. Например:

Нахождение шестнадцатеричных кодов цвета

Функция позволяет находить или проверять правильность шестнадцатеричных кодов цвета.

Нахождение заголовка страницы

Данный код найдет и выведет на экран текст между тегами и HTML страницы.

Парсинг логов Apache

Многие сайты работают на веб-сервере Apache. Если ваш сайт тоже работает на тако сервере, то следующие регулярки могут пригодиться.

Замена двойных кавычек на фигурные

Проверка сложности пароля

Это регулярное выражение проверяет строку по пунктам: строка должна содержать не менее 6 букв, цифр, подчеркиваний и тире. Строка должна содержать хотя бы одну заглавную букву, строчную и цифру.

WordPress: Получение изображений поста с помощью регулярного выражения

Если вы используете WordPress вам может пригодиться функция, которая получит все изображения из поста и покажет их. Для использования данного кода, скопируйте его в файлы своей темы.

Преобразование смайлов в картинки

Эта функция также есть в WordPress, она позволяет автоматически заменить текстовые смайлы на картинки.

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

Функции сравнения строк и поиска подстрок, рассмотренные в предыдущей статье, позволяют успешно справляться с теми задачами, для которых они предназначены, но имеют существенные ограничения в том, что основаны на использовании литеральных значений. В качестве иллюстрации того, в чем состоят ограничения этих функций, рассмотрим следующий пример. Предположим, требуется выполнить проверку строк для определения того, относятся ли эти строки к конкретному типу имени хоста веб-сайта. Адреса, представленные этим именем, должны начинаться с подстроки www., оканчиваться подстрокой .com и иметь в середине одно слово, состоящее из прописных букв. В качестве примера ниже приведены строки, имеющие требуемый формат:

А эти строки не соответствуют указанным требованиям:

Даже краткие размышления показывают, что в нашем распоряжении пока что нет удобного способа, позволяющего воспользоваться средствами сравнения строк и подстрок для проведения требуемой проверки. Мы можем проверить наличие подстрок www. и .com, но гораздо сложнее проверить соответствие заданным требованиям той подстроки, которая находится между ними. Однако с этой задачей позволяют легко справиться регулярные выражения.

Для сокращенного обозначения регулярных выражений в английском языке применяется термин . Регулярные выражения представляют собой шаблоны для согласования со строками, содержащие специальные подстановочные символы, которые могут быть согласованы с целыми фрагментами целевой строки. Язык PHP позволяет применять два широких класса регулярных выражений: регулярные выражения, совместимые со стандартом POSIX (называемые расширенными), и обычные регулярные выражения, совместимые с языком Perl. Различия между этими классами в основном касаются синтаксиса, но имеются также некоторые функциональные различия.

В конечном итоге регулярные выражения в стиле POSIX явились итогом развития средств сопоставления с шаблонами регулярных выражений, используемых в интерпретаторах Unix с интерфейсом командной строки, а регулярные выражения, совместимые с языком Perl, в большей степени напоминают соответствующие средства указанного языка. Любой разработчик, которому предстоит выполнить хоть сколько-нибудь существенный объем программирования в среде веб, рано или поздно будет вынужден воспользоваться регулярными выражениями.

Начиная с версии PHP 5.3.0 функции для работы с регулярными выражениями в стиле POSIX являются устаревшими, поэтому далее мы будем рассматривать регулярные выражения в стиле Perl.

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

Для обработки регулярных выражений, совместимых с языком Perl, в языке PHP применяется полностью отдельный набор функций, а формирование шаблонов осуществляется следующим образом:

Шаблоны регулярных выражений, совместимых с языком Perl, всегда начинаются и оканчиваются одним конкретным символом, который должен быть одинаковым и в начале и в конце. Этот символ отмечает начало и конец шаблона. В соответствии с общепринятым соглашением для этой цели чаще всего используется символ /, но при желании может также применяться другой символ. Следующий шаблон, совместимый с языком Perl: /pattern/, согласуется с любой строкой, которая содержит в себе строку (вернее, подстроку) «pattern».

Сопоставление символов с такими же символами, которые не являются специальными, осуществляется непосредственно. Например, буква в шаблоне согласуется с той же буквой в целевой строке.

Специальный символ ^ согласуется только с началом строки, а специальный символ $ — только с концом строки.

Специальный символ . согласуется с любым символом.

Специальный символ * обеспечивает согласование заданного перед ним регулярного выражения в количестве от нуля или больше, а символ + указывает, что согласование достигается, если количество обнаруженных в целевой строке экземпляров стоящего перед ним регулярного выражения составляет от одного и больше.

Набор символов, заключенный в квадратные скобки, согласуется с любым из символов этого набора. Например, шаблон [ab] согласуется и с буквой a, и с буквой b. В квадратных скобках можно также определить диапазон символов с использованием дефиса. Например, шаблон [a-c] согласуется с буквой a, b или c.

Специальные символы, отмеченные знаком переключения режима обработки в виде обратной косой черты (\), теряют свое специальное значение и сопоставляются непосредственно, как обычные символы.

Если рассматриваемый символ не является специальным, то шаблон в стиле Perl последовательно согласует символы. Например, шаблон /abc/ согласуется с любой строкой, которая содержит подстроку «abc»

Любой шаблон, за которым следует символ ? (вопросительный знак), означает: «Выполнить согласование конструкции, предшествующей этому символу, нуль или один раз».

Любой символ, который имеет в регулярном выражении специальное значение, может быть преобразован в простой, буквально согласуемый символ путем введения перед ним префикса в виде обратной косой черты (знак переключения на другой режим обработки). Специальные символы, которые требуют применения знака переключения, чтобы можно было выполнять согласование с их буквальными значениями, перечислены ниже.

Круглые скобки, выделяющие любую часть шаблона, означают: «Добавить подстроку, которая согласуется с этим подвыражением, к списку подстрок, согласованных с шаблоном»

Рассмотрим в качестве примера следующий шаблон:

Он согласуется с любой строкой, содержащей литеральное выражение «тел.», за которым следует какое-то количество пробелов (но не меньше одного), после чего приведено точно семь цифр (без пробелов и дефисов). Кроме того, в этом шаблоне заданы круглые скобки, поэтому номер, состоящий из семи цифр, сохраняется и возвращается в виде массива, содержащего подстроки сопоставления, если данный шаблон вызывается из функции, которая возвращает подобные объекты.

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

Специальные символы регулярных выражений PHP

Классы символов
[. ] Любой из символов, указанных в скобках
[^. ] Любой из символов, не указанных в скобках
. Любой символ, кроме перевода строки или другого разделителя Unicode-строки
\w Любой символ, образующий «слово»
\W Любой символ, не являющийся текстовым символом
\s Любой пробельный символ из набора Unicode
\S Любой непробельный символ из набора Unicode. Обратите внимание, что символы \w и \S — это не одно и то же
\d Любые ASCII-цифры. Эквивалентно [0-9]
\D Любой символ, отличный от ASCII-цифр. Эквивалентно [^0-9]
Символы повторения
Соответствует предшествующему шаблону, повторенному не менее n и не более m раз
Соответствует предшествующему шаблону, повторенному n или более раз
Соответствует в точности n экземплярам предшествующего шаблона
? Соответствует нулю или одному экземпляру предшествующего шаблона; предшествующий шаблон является необязательным. Эквивалентно
+ Соответствует одному или более экземплярам предшествующего шаблона. Эквивалентно
* Соответствует нулю или более экземплярам предшествующего шаблона. Эквивалентно
Символы регулярных выражений выбора
| Соответствует либо подвыражению слева, либо подвыражению справа (аналог логической операции ИЛИ).
(. ) Группировка. Группирует элементы в единое целое, которое может использоваться с символами *, +, ?, | и т.п. Также запоминает символы, соответствующие этой группе для использования в последующих ссылках.
(. ) Только группировка. Группирует элементы в единое целое, но не запоминает символы, соответствующие этой группе.
Якорные символы регулярных выражений
^ Соответствует началу строкового выражения или началу строки при многострочном поиске.
$ Соответствует концу строкового выражения или концу строки при многострочном поиске.
\b Соответствует границе слова, т.е. соответствует позиции между символом \w и символом \W или между символом \w и началом или концом строки.
\B Соответствует позиции, не являющейся границей слов.
(?=p) Позитивная опережающая проверка на последующие символы. Требует, чтобы последующие символы соответствовали шаблону p, но не включает эти символы в найденную строку.
(?!p) Негативная опережающая проверка на последующие символы. Требует, чтобы следующие символы не соответствовали шаблону p.
\A начало данных (независимо от многострочного режима)
\Z конец данных либо позиция перед последним переводом строки (независимо от многострочного режима)
Флаги (указываются в конце рег. выражения)
i Указывает, что поиск по шаблону должен быть нечувствителен к регистру символов.
m Многострочный режим поиска (multiline).
s Если данный модификатор используется, метасимвол «точка» в шаблоне соответствует всем символам, включая перевод строк.
x Если используется данный модификатор, неэкранированные пробелы, символы табуляции и пустой строки будут проигнорированы в шаблоне, если они не являются частью символьного класса.

Общие сведения о функциях, совместимых с языком Perl, приведены в таблице ниже:

Функции PHP для работы с регулярными выражениями, совместимые с языком Perl

Принимает в качестве первого параметра шаблон регулярного выражения, второго параметра — строку, с которой должно быть выполнено согласование, и необязательного третьего параметра — переменную типа «массив» для возвращаемых результатов согласования. Возвращает 0, если согласование не найдено, и 1, если согласование найдено.

В случае успешного согласования переменная типа «массив» содержит следующие элементы: первым элементом является вся согласованная подстрока, а последующие элементы содержат части, соответствующие заключенным в круглые скобки подвыражениям шаблона. Начиная с версии PHP 4.3.0 предусмотрена также возможность задать необязательный флаг PREG_OFFSET_CAPTURE. Этот флаг вынуждает функцию preg_match() возвращать в указанном массиве в расчете на каждое согласование по одному двухэлементному массиву, состоящему из самих результатов согласования и информации о смещении, с которого было начато успешное согласование.

Аналогична preg_match(), за исключением того, что осуществляет все возможные подряд идущие согласования шаблона со строкой, а не только первое согласование. Возвращаемым значением является количество успешно выполненных согласований. В этой функции третий параметр, массив согласований, является обязательным (если требуется получение только истинного или ложного значения, которое показывает наличие или отсутствие согласования, используйте функцию preg_match()). Структура возвращаемого массива зависит от необязательного четвертого параметра (в качестве этого параметра служит константа PREG_PATTERN_ORDER или PREG_SET_ORDER, причем по умолчанию применяется первая). При вызове этой функции можно также применять константу PREG_OFFSET_CAPTURE (эти константы описываются далее).

Принимает в качестве первого параметра шаблон регулярного выражения и второго параметра — строку, с которой должно быть выполнено согласование. Возвращает массив, содержащий результаты разбиения строки на подстроки в местах вхождения разграничительных строк, согласующихся с шаблоном. Необязательный третий параметр (с обозначением предельного количества) указывает, на какое количество подстрок должна быть разбита строка, прежде чем будет возвращен полученный список; значение -1 в позиции третьего параметра указывает на то, что предел не устанавливается. В качестве необязательного четвертого параметра может быть задан флаг PREG_SPLIT_NO_EMPTY (вынуждающий функцию возвращать только непустые части), PREG_SPLIT_DELIM_CAPTURE (которое требует возврата всех подстрок, соответствующих заключенным в круглые скобки выражениям в шаблоне разграничителя) или PREG_OFFSET_CAPTURE.

Функция Описание
preg_match()
preg_match_all()
preg_split()
preg_replace() Принимает в качестве параметров шаблон, строку замены и строку, в которой должны быть внесены изменения. Возвращает модифицированную строку, в которой вместо каждой подстроки, согласованной с шаблоном, подставлена строка замены. Необязательный параметр с обозначением предельного количества определяет, сколько должно быть выполнено замен (как в функции preg_split())
preg_replace_callback() Эта функция аналогична функции preg_repiace(), за исключением того, что вторым параметром является имя функции обратного вызова, а не строка замены. Эта функция должна возвращать строки, предназначенные для использования в качестве замены
preg_grep() Принимает в качестве параметров шаблон и массив и возвращает массив, состоящий из элементов входного массива, который сопоставляется с шаблоном. Значения, перешедшие из старого массива в новый массив, имеют такие же ключи, как и соответствующие элементы исходного массива
preg_quote() Функция специального назначения, предназначенная для вставки знаков переключения на другой режим обработки в строки, которые предназначены для использования в качестве шаблонов регулярных выражений. Для этой функции требуется единственный параметр—строка, в которую должны быть вставлены знаки переключения; возвращаемым значением является та же строка, в которой перед каждым специальным символом регулярного выражения вставлена обратная косая черта (знак переключения)

По-видимому, наиболее широко используемыми из этих функций являются preg_match() и preg_match_all(). Первая функция представляет собой наилучшее средство получения ответа на простой вопрос о том, сопоставляется ли некоторый шаблон с некоторой строкой, а последняя функция является удобным средством подсчета количества согласований или получения сразу всех согласующихся подстрок.

Необязательный четвертый параметр функции preg_match_all() требует дополнительных пояснений. Как правило, массив, который содержит возвращаемые результаты согласования, имеет двухуровневую структуру. На первом уровне показана очередность сопоставлений (первое сопоставление, второе и т.д.), а на втором показана позиция сопоставления в шаблоне. (Все сопоставление всегда находится на первом месте, а за ним следуют по порядку все субшаблоны, обозначенные круглыми скобками.) Вопрос заключается в следующем: «Какой уровень является самым верхним? Будет ли возвращаемый массив представлять собой список элементов с указанием позиций, каждый из которых содержит список номеров последовательных согласований, или данный массив имеет обратную структуру?»

Если четвертым параметром является PREG_PATTERN_ORDER, то первый элемент содержит данные обо всех сопоставлениях с субшаблонами во всем шаблоне, второй элемент содержит данные обо всех сопоставлениях с первым субшаблоном, заключенным в круглые скобки, и т.д. Если же в качестве четвертого параметра применяется флажок PREG_SET_ORDER, то первый элемент представляет собой список всех подстрок из первого сопоставления (в этом списке в начале представлены общие результаты сопоставления, а затем последовательно приведены результаты сопоставления с субшаблонами, заключенными в круглые скобки), второй элемент содержит все подстроки из второго сопоставления и так далее (в следующем разделе приведен пример, который может служить иллюстрацией к этому описанию).

Давайте рассмотрим сначала простой пример, в котором извлекаются все телефонные номера из подстроки и выбирается код страны, код города и номер:

Код PHP «; // Шаблон регулярного выражения $pattern = ‘/(\d+)[\s|\(|-]*([\d]<3,>)[\s|\)|-]*([\d|-]+)/’; preg_match_all($pattern, $str, $arr, PREG_SET_ORDER); foreach ($arr as $entry) < echo "

Этот код даст следующий результат:

Использование регулярных выражений для поиска телефонных номеров

Я могу долго объяснять принцип работы представленного в примере регулярного выражения, но я лучше покажу:

Схема использования регулярного выражения

Пример: программа извлечения ссылок

В качестве более сложного примера того, какие действия могут быть выполнены с помощью регулярных выражений, рассмотрим функцию, позволяющую извлекать ссылки из текста произвольной веб-страницы и выводить полученные результаты на экран. Входными данными служит URL страницы, которая должна быть проанализирована, а выходными данными являются выведенный на экран список ссылок, представленных на соответствующей странице. Этот список состоит из целевого URL для данной ссылки и описательного текста, присутствующего в этой ссылке (который принято называть анкором (или якорем ссылки)). Для решения указанной задачи используются функции для работы с регулярными выражениями, совместимыми с языком Perl.

Разработка такой функции может стать самым первым шагом при создании веб-навигатора для поисковой машины. Поисковики (Google, Yandex и т.п.) загружают содержимое веб-страниц для их анализа и индексации. В ходе работы возникает необходимость распознавать ссылки на другие страницы, если новое информационное наполнение можно будет найти только на этих страницах.

Основное регулярное выражение

Основой разрабатываемой небольшой функции должно служить само регулярное выражение. Необходимо прежде всего разработать такое регулярное выражение, которое сопоставляется только со ссылками HTML (и ничем иным) и может применяться для извлечения фрагментов таких ссылок. Ссылки HTML, как правило, выглядят таким образом:

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

Прежде всего необходимо отметить, что регулярные выражения, рассматриваемые как единое целое, считаются весьма трудными для восприятия (в этом вы могли убедиться на примере выше). Поэтому регулярное выражение, предназначенное для решения данной задачи, будет создаваться на основе нескольких черновых вариантов, описание которых приведено по ходу изложения.

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

Обратите внимание на то, что разрабатываемый шаблон еще не предназначен для использования в работоспособном коде PHP; в данном случае создается черновой вариант выражения, которое должно быть вставлено в код PHP позднее. На обычном языке первое черновое определение дескриптора анкора можно описать как состоящее из левой угловой скобки, за которой следует буква «a», затем — пробел, вслед за ним — строка «href=», знак двойной кавычки, произвольное количество символов, отличных от знаков кавычки, заключительный знак кавычки и, наконец, правая угловая скоба. После его составления все выражение заключается в пару символов косой черты, которые служат для машины обработки регулярных выражений указанием на то, где начинается и оканчивается выражение.

Конструкция [^»]+ в середине этого выражения означает примерно следующее: квадратные скобки указывают применяемый набор символов, а знак вставки (^), который непосредственно следует за левой скобкой, указывает, что используется отрицание этого множества символов. Таковым является множество, содержащее все символы, не находящиеся в последующем списке. Наконец, знак + после обозначения класса символов, заключенного в квадратные скобки, показывает, что подразумевается наличие в шаблоне по меньшей мере одного символа, отличного от кавычки.

Как уже было сказано, мы не ставили перед собой задачу точно отразить синтаксис, предписанный спецификацией HTML. Однако существует целый ряд способов, с помощью которых можно немного ослабить ограничения, налагаемые этим выражением. Прежде всего, насколько известно, количество пробелов между начальным символом Код PHP

В качестве текста анкора допускается использовать любой текст, который занимает на странице место вплоть до заключительного дескриптора анкора, поэтому создается класс символов, который включает любые символы, кроме правой угловой скобой ([^>]*), и указывает, что данные символы могут присутствовать в количестве от нуля и больше. Наконец, вводится субшаблон для сопоставления с закрывающим дескриптором анкора ( ).

Применение данного шаблона вполне обеспечивает обработку дескрипторов анкора в том виде, который используется в качестве исходного определения, но обеспечивает сопоставление только с такими анкорами, в которых имя дескриптора (а) и атрибут (href) заданы строчными буквами. Однако допускается с тем же успехом использовать дескрипторы с прописными буквами, поэтому добавим модификатор i после всего выражения, чтобы указать на режим сопоставления без учета регистра:

Этот черновой вариант является почти полностью законченным и может использоваться для получения положительного или отрицательного ответа на вопрос о том, содержит ли страница ссылки такого типа, который нам требуется. Но мы обязаны провести дополнительную работу и извлечь определенные фрагменты любой строки, сопоставляемой с шаблоном. Для указания на это вводятся круглые скобки, заключающие в себе те подстроки, которые нас интересуют (в этом выражении добавлен модификатор x, чтобы экранировать пробелы в рег. выражении, которые вводятся для его удобочитаемости):

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

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

После получения необходимого выражения для сопоставления с дескриптором анкора можно приступить к решению следующей задачи — написанию функции, извлекающей ссылки с HTML-страницы. Для этого необходимо осуществить описанные ниже действия:

Принять в качестве параметра заданный URL.

Открыть соединение HTTP с помощью указанного URL и получить информационное наполнение страницы в виде строки.

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

Вывести на экран все пары извлеченных подстрок (состоящие из целевого URL и текста анкора).

В примере ниже показана полная структура целевой страницы включая функцию print_links():

Простая программа поиска ссылок на PHP

Задача разработки этой функции проще, чем кажется на первый взгляд, поскольку в языке PHP уже предусмотрены многие ее составляющие. В частности, не требуется предусматривать каких-либо особых действий по созданию соединения HTTP для загрузки веб-страницы, поскольку функция fopen() принимает URL в качестве параметра и выполняет все необходимое. Поэтому достаточно после вызова функции fopen() с указанным в ней URL считывать символы до тех пор, пока поступление этих символов не прекратится, добавляя полученные данные к создаваемой строке.

Обработка в цикле содержимого HTML-страницы обеспечивается с помощью функции preg_match_all(). В этой функции шаблон регулярного выражения применяется максимально возможное количество раз, после каждого использования обработка строки начинается непосредственно вслед за тем участком, где перед этим было обнаружено совпадение с шаблоном, и результаты поиска сохраняются в массиве $match_array. Здесь мы решили применить структуру массива, упорядоченную в соответствии с флажком PREG_SET_ORDER. Это означает, что каждая запись в массиве верхнего уровня представляет собой часть, соответствующую результатам конкретного согласования с шаблоном в текущей итерации, а не часть, полученную в результате всех согласований.

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

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

Основные функции для работы с Perl-совместимыми регулярными выражениями:

preg_match(pattern, string, [result, flags]) и preg_match_all(pattern, string, result, [flags]), где:

  • pattern – шаблон регулярного выражения;
  • string – строка, в которой производится поиск;
  • result – содержит массив результатов (нулевой элемент массива
    содержит соответствие всему шаблону, первый – первому «захваченному» подшаблону и т.д.);
  • flags – необязательный параметр, определяющий то, как упорядочены результаты поиска.

Эти функции осуществляют поиск по шаблону и возвращают информацию о том, сколько раз произошло совпадение. Для preg_match() это 0 (нет совпадений) или 1, поскольку поиск прекращается, как только найдено первое совпадение. Функция preg_match_all() производит поиск до конца строки и поэтому находит все совпадения. Все точные совпадения содержатся в первом элементе массива result у каждой из этих функций (для preg_match_all() этот элемент – тоже массив).

Аналогом preg_match является булева функция POSIX-расширения ereg(string pattern, string string [, array regs]).
Функция ereg() возвращает TRUE, если совпадение найдено, и FALSE – в противном случае.

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

Синтаксис регулярных выражений

Регулярное выражение представляет собой строку. Эта строка состоит из собственно регулярного выражения (шаблона), выделенного с помощью специального символа разделителя (это могут быть символы «/» , «|», «<«, «!» и т.п ) и модификатора, влияющего на способ обработки РВ.

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

Одним из основных метасимволов является обратный слэш «\». Он меняет тип символа, следующего за ним, на противоположный, т.е. если это был обычный символ, то он МОЖЕТ превратиться в метасимвол, если это был метасимвол, то он теряет свое специальное значение и становится обычным символом (это нужно для того, чтобы вставлять в текст специальные символы как обычные).
Например, символ d в обычном режиме не имеет никаких специальных значений, но \d есть метасимвол, означающий «любая цифра». Символ «.» в обычном режиме означает «любой единичный символ», а «\.» означает просто точку.

Другое назначение обратного слэша – кодирование непечатных символов, таких как:

  • \n – cимвол перевода строки;
  • \e – символ escape;
  • \t – cимвол табуляции;
  • \xhh – символ в шестнадцатеричном коде, например \x41 есть буква A и т.д.

Еще одно назначение обратного слэша – обозначение генерируемых символьных типов, таких как:

  • \d – любая десятичная цифра (0-9);
  • \D – любой символ, не являющийся десятичной цифрой;
  • \s – любой пустой символ (пробел или табуляция);
  • \S – любой символ, не являющийся пустым;
  • \w – символ, используемый для написания Perl-слов (это буквы, цифры и символ подчеркивания), так называемый «словарный символ»;
  • \W – несловарный символ (все символы, кроме определяемых \w).

Что имеется в виду под «символьным типом»? Просто каждый метасимвол принимает значение (одно) из класса возможных значений, заданных автоматически или вручную. Символьные типы, задаваемые пользователем, описываются с помощью квадратных скобок (подробнее об этом позже). Выше приведены символьные типы, диапазон значений которых заранее определен языком программирования.

Пример использования приведенных выше метасимволов:

Это РВ означает: трехзначное число, за которым следует подстрока plus, любая цифра, затем is и слово из трех словарных символов.

В частности, данному РВ удовлетворяют строки: «123 plus 3 is sum», «213 plus 4 is 217».

Вообще различают два множества метасимволов: те, что распознаются в любом месте шаблона, за исключением внутренности квадратных скобок, и те, что распознаются внутри квадратных скобок. Квадратные скобки [ ] применяются для описания подмножеств и внутри регулярного выражения рассматриваются как один символ, который может принимать значения, перечисленные внутри этих скобок. Однако если первым символом внутри скобок является ^, то значением символьного класса могут быть только символы, НЕ перечисленные внутри скобок.

  • 1. Символьный класс [абвгд] задает один из символов а, б, в, г, д, а; класс [^абвгд] задает любой символ, кроме а, б, в, г, д.
  • 2. Если написать [2бул]ки], то это выражение интерпретируется как один из символов 2, б, у, л, за которым следует строка ки], потому что первая встретившаяся закрывающая квадратная скобка (разбор происходит слева направо) заканчивает определение символьного класса. То есть это РВ совпадет с одной из строк 2ки], бки], уки] или лки].
  • 3. С помощью РВ [0-9А-Яа-я] можно задать любую букву или цифру.

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

0. Пусть дан такой текст, записанный в виде строки:
$str = «11 aaa bbb «.
«ccc 22 ddd «.
«eee ggg 33»;

Метасимволы, распознаваемые ВНУТРИ квадратных скобок:

  • \ — Переходный символ со множеством назначений
  • ^ — Отрицание класса, но только если это первый символ (например, «^\d» задает все, кроме цифр)
  • — Задает диапазон символов (например, «0-9» задает все цифры, «A-Z» – все латинские буквы)
  • ] — Вычисляет символьный класс

Регулярное выражение /\d\d/m может быть сопоставлено следующим подстрокам: 11, 22, 33. Если в начале РВ стоит ^, то совпадения ищутся в начале строки, поэтому выражение /^\d\d/m найдет только 11.

Когда в конце РВ стоит знак доллара $, поиск производится в конце строки, поэтому выражение /\d\d$/m найдет только 33.

Шаблону же /^\d\d\d$/ будет удовлетворять строка, целиком состоящая из трехзначного числа (т.е. она и начинается и заканчивается этим числом).

1. Найдем все html-теги, расположенные в начале каждой строки файла 1.htm.

Шаблон «!^ !mU» ограничен восклицательными знаками. Первая «^» значит, что мы ищем совпадения в начале строк, потом идет символ « ». Таким образом, выделяются все теги в начале строк.

Метасимволы, распознаваемые ВНЕ квадратных скобок:

  • \ — Переходный символ со множеством назначений
  • ^ — Объявляет начало объекта (или строки в многострочном режиме). То есть этот символ определяет, что искомый текст должен находиться в начале строки. Альтернатива: «\A»
  • $ — Объявляет конец объекта (или строки в многострочном режиме). То есть этот символ определяет, что искомый текст должен находиться в конце строки. Альтернативы: «\Z», «\z»
  • . — Совпадает с любым символом, кроме символа перевода строки (по умолчанию)
  • [ — Начинает определение символьного класса
  • ] — Заканчивает определение символьного класса
  • | — Разделяет перечисление альтернативных вариантов
  • ( — Начинает подшаблон регулярное (подвыражение)
  • ) — Заканчивает подшаблон
  • ? — Расширяет значение «(», квантификаторов 0 или 1, и квантификатор минимизации
  • * — 0 или больше повторений (квантификатор)
  • + — 1 или больше повторений (квантификатор)
  • <— Начинает минимальный/максимальный квантификатор
  • > — Заканчивает минимальный/максимальный квантификатор

2. Мы хотим убедиться, что имя автора было записано правильно (сначала фамилия с большой буквы, потом инициалы через точку) и находится в конце строки.

Примеры использования метасимволов ( | и .)

1. Пусть имеется некий текст. Нам нужно найти всех упомянутых в нем людей со званиями.

Метасимвол прямая черта « | » позволяет задавать альтернативные варианты. В примере мы хотели найти всех профессоров или доцентов. Для этого было создано подвыражение «(профессор|доцент)». После звания через пробел фамилия человека, которому оно принадлежит, – для этого существует комбинация «\s[А-Я][А-Яа-я]+». После фамилии идет либо опять пробел, либо точка, если это конец предложения. Получаем опять два альтернативных варианта: «(\s|\.)» (здесь точка экранируется обратным слэшем, чтобы она понималась как обычная точка, без специального значения).

Подвыражения (подшаблоны)

В нескольких примерах мы уже использовали подвыражения. Настало время разобраться, что же это такое и
какими свойствами они обладают
В РВ подшаблоны выделяют, заключая в круглые скобки.
Для их обозначения кроме термина «подшаблон» также используют термин «подвыражение».
Подшаблоны могут быть вложенными. Выделение части регулярного выражения в виде регулярного подвыражения делает следующее.

1. Локализует множество альтернатив.
Например, шаблон
жар(кое|птица|)

совпадает с одним из слов «жаркое», «жарптица» и «жар». Тогда как без скобок это было бы «жаркое», «птица» и пустая строка.

2. Устанавливает подшаблон как «захватывающий» подшаблон. Это значит, что, когда какая-то подстрока в тексте совпала с шаблоном, все подстроки, которые совпали с подшаблонами этого РВ, тоже возвращаются в качестве результата. Скобки, обозначающие начало подшаблона, пересчитываются слева направо (начиная с 1) для того, чтобы узнать, сколько подшаблонов нужно захватить.
Например, имеется такой шаблон:
победитель получит
((золотую|позолоченный)
(медаль|кубок))

и строка, в которой ищутся совпадения с этим шаблоном: «победитель получит золотую медаль». Тогда кроме этой фразы будут еще захвачены и выданы как результаты поиска следующие совпадения в подвыражениях: «золотую медаль», «золотую», «медаль», пронумерованные 1, 2, 3 соответственно.

Однако это не всегда удобно. Для того чтобы избавиться от «захватывающего» эффекта подвыражения, после открывающей скобки пишут «?:». Тогда это подвыражение в результат поиска не включается и при нумерации остальных подшаблонов с «захватывающим» эффектом не учитывается.
победитель получит
((?:золотую|позолоченный)
(медаль|кубок))

Тогда в условиях предыдущего примера получим искомую строку «победитель получит золотую медаль» и строки «золотую медаль», «медаль», пронумерованные 1 и 2 соответственно.

Если в html-файле название находится после и отделено от него только пробелами или переводами строк, заключено в тег

и
после него тоже может идти сколько-то пробелов и переводов строк, то его можно найти с помощью следующего скрипта:

Заметим, что здесь выводится первое захваченное подвыражение, поскольку нам интересно только само название, а не все РВ. Так как в этом РВ есть только одно подвыражение, то его значение содержится в нулевом элементе первого массива результатов.
Повторения (квантификаторы)

Повторения описываются с помощью так называемых квантификаторов (метасимволов, задающих количественные отношения).
Существует два типа квантификаторов: общие (задаются с помощью фигурных скобок) и сокращенные (это исторически сложившиеся
сокращения наиболее распространенных квантификаторов).

Квантификаторы могут следовать за любым из перечисленных элементов:

  • одиночный символ (возможно, в комбинации с обратным слэшем);
  • метасимвол «.»;
  • символьный класс;
  • обратная ссылка (о них расскажем позднее);
  • подшаблон.

Общие квантификаторы задают минимальное и максимальное число дозволенных повторений элемента;
эти два числа, разделенные запятой, заключаются в фигурные скобки. Числа не должны превышать
65 536 и первое число должно быть меньше или равно второму. Например, x говорит о том,
что символ «x» должен повторяться минимум один, а максимум три раза.
Соответственно этому шаблону удовлетворяют строки: x, xx, xxx.

Если второй параметр отсутствует, но запятая есть, то повторений может быть сколько угодно.
Таким образом, [aeuoi] значит, что любой из символов «a», «e», «u», «o», «i»
в строке может повторяться два и более раз, а регулярное выражение \d
задает ровно три цифры.

Сокращенные квантификаторы задают наиболее используемые количественные отношения (повторения).
Они придуманы для удобства, чтобы не перегружать и без того сложные выражения лишним синтаксисом.

Исходя из исторических традиций три наиболее часто встречающихся квантификатора имеют следующие обозначения:

  • * эквивалентно <0,>– то есть это ноль и более повторений;
  • + эквивалентно <1,>– то есть это одно и более повторений;
  • ? эквивалентно <0,1>– то есть это ноль или одно повторение.

Есть еще один важный момент, на который стоит обратить внимание при изучении квантификаторов.
По умолчанию все квантификаторы «жадные», они стараются захватить как можно
больше повторений элемента. То есть если указать, что символ должен повторяться один и более раз
(например, с помощью *), совпадение произойдет со строкой, содержащей наибольшее число повторений
указанного символа. Это может создать проблемы, например, при попытке выделить комментарии в
программе на языке Cи или PHP. Комментарии в Cи и PHP записываются между символами /* и */,
внутри которых тоже могут встречаться символы * и /. И попытка выявить Си-комментарии с помощью шаблона
/\* .* \*/ в строке /* первый комментарий */ не комментарий /* второй комментарий */
не увенчается успехом из-за «жадности» элемента «.*» (будет найдена также строка «не комментарий»).
Для решения этой проблемы нужно написать знак вопроса после квантификатора. Тогда он перестанет быть
«жадным» и попытается захватить как можно меньшее число повторений элемента, к которому он применен
(квантификатор применяется к элементу, что стоит перед ним). Так что шаблон /\* .*? \*/
успешно выделяет Си-комментарии.

В PHP существует опция PCRE_UNGREEDY, которая делает все квантификаторы «не жадными» по умолчанию и «жадными», если после них идет знак вопроса.

HackWare.ru

Этичный хакинг и тестирование на проникновение, информационная безопасность

Регулярные выражения в PHP (ч. 2)

Оглавление

Первая часть:

Вторая часть:

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

Общие типы символов

Теперь мы опять вернёмся к синтаксису, который может использоваться при написании регулярных выражений. В отличие от ранее рассмотренных основ, описанное ниже является более сложным и применяется реже, либо может быть описано с помощью уже рассмотренного синтаксиса.

Например, далее рассмотрены способы указания общего типа символов — некоторые из этих способов записи являются альтернативным синтаксисом к уже рассмотренным. Допустим если мы хотим указать в регулярном выражении «любая цифра», то мы можем использовать [0-9]. Также имеется ещё один вариант записи с помощью экранирующих последовательностей. «Любая десятичная цифра» в них обозначается как \d.

Экранирующие последовательности — это набор символов, которые начинаются с обратного слэша \ и, следовательно, которые теряют своё буквальное значение, а начинают иметь специальное значение. Получается, что для специальных символов обратный слэш отключает их специальное значение, а для обычных букв и цифр он включает специальное значение (если оно предусмотрено).

Среди экранирующих последовательностей есть элементы синтаксиса, который невозможно передать иным способом. Примеры будут показаны далее.

Общие типы символов обозначаются так:

\d

любая десятичная цифра

\D

любой символ, кроме десятичной цифры

\h

любой горизонтальный пробельный символ

\H

любой символ, не являющийся горизонтальным пробельным символом

\s

любой пробельный символ

\S

любой непробельный символ

\v

любой вертикальный пробельный символ

\V

любой символ, не являющийся вертикальным пробельным символом

\w

Любой символ, образующий «слово»

\W

Любой символ, не образующий «слово»

Каждая пара таких специальных последовательностей делит полное множество всех символов на два непересекающихся множества. Любой символ соответствует одному и только одному множеству из пары.

Следующие символы считаются как «пробельные»: HT (9), LF (10), FF (12), CR (13), и пробел (32). Тем не менее, если идет локале-зависимый поиск, и произойдет совпадение с символами в диапазоне 128-255, они также будут восприняты как пробельные, например NBSP (A0).

Символ, образующий «слово» — это произвольная цифра, буква или символ подчеркивания, проще говоря, любой символ, который может являться частью «слова» в Perl. Определение букв и цифр управляется символьными таблицами, с которыми была собрана PCRE. И, как следствие, эти наборы могут отличаться в различных локализированных дистрибутивах. Например, в локали «fr» (Франция) некоторые символы с кодом выше 128 используются для записи ударных символов и, соответственно, соответствуют маске \w.

Описанные выше типы символов могут применяться как внутри, так и вне символьных классов, и соответствуют одному символу данного типа. Если текущая точка сравнения находится в конце строки, ни один из них не сможет совпасть, так как нет символа, с которым могло бы произойти совпадение.

У этих символов может быть весьма полезное применение. Давайте вспомним (чуть переделанное) регулярное выражение для вывода HTML тэга всех заголовков вместе с конечным тегом, а также вместе с самим содержанием заголовка:

Используя уже известный код:

я получил вот такой результат:

Найдено всего 15 совпадений, хотя мы помним, что на этой странице заголовков намного больше. Дело в том, что найдены только заголовки, которые в HTML коде записаны в одну строку, например так:

А если запись разбита на несколько строк, например так:

то такие заголовки найдены не были.

Проблема не в каких-то ограничениях регулярных выражений — в PHP анализ текста происходит именно целиком, то есть даже если текст состоит из нескольких строк, в PHP он анализируется за раз, без разбития на строки.

Проблема в нашем регулярном выражении, которое мы написали — мы не указали, что после открывающего тэга заголовка могут идти пробелы. Затем после содержимого заголовка также могут идти пробелы. Давайте составим новое регулярное выражение, с учётом этого. Любые пробельные символы обозначаются как \s. Их может не быть вовсе, а может быть несколько, поэтому в качестве квантора нужно использовать звёздочку, получаем \s*. Эту конструкцию вставляем два раза: 1) между открывающим HTML тэгом и содержимым заголовка; 2) между концом содержимого заголовка и закрывающим HTML тэгом.

Получаем такое регулярное выражение:

В результате находим 51 заголовок — видимо, это все заголовки анализируемой страницы, среди них как написанный в одну строку, так и многострочные.

В подобных случаях также можно использовать модификатор регулярного выражения s. Подробности и примеры смотрие в статье «Поиск по нескольким строкам в PHP с функциями preg_match_all и preg_match».

Следующие два раздела (непечатные символы и определение формальных утверждений) — нечасто применимы, поэтому если вы в них не разобрались, то просто переходите к последующим параграфам.

Непечатные символы в видимой форме в описании шаблона

В PCRE нет ограничений на использование непечатных символов (исключая бинарный ноль, который интерпретируется как конец шаблона), тем не менее, при редактировании программного кода в каком-либо текстовом редакторе гораздо удобнее использовать следующие комбинации, чем реальные символы, которые они представляют:

\a

символ оповещения, сигнал, (BEL, шестнадцатеричный код 07)

\cx

«Ctrl+x«, где x — произвольный символ

\e

escape (шестнадцатеричный код 1B)

\f

разрыв страницы (шестнадцатеричный код 0C)

\n

перевод строки (шестнадцатеричный код 0A)

символ со свойством xx, подробнее смотрите свойства unicode

символ без свойства xx, подробнее смотрите свойства unicode

\r

возврат каретки (шестнадцатеричный код 0D)

\R

разрыв строки: совпадает с \n, \r и \r\n

\t

табуляция (шестнадцатеричный код 09)

\xhh

символ с шестнадцатеричным кодом hh

\ddd

символ с восьмеричным кодом ddd, либо ссылка на подмаску

Если быть более точным, комбинация «\cx» интерпретируется следующим образом: если «x» — символ нижнего регистра, он преобразуется в верхний регистр. После этого шестой бит символа (шестнадцатеричный код 40) инвертируется. Таким образом «\cz» интерпретируется как шестнадцатеричное значение 1A, в то время как «\c<" получает шестнадцатеричное значение 3B, а "\c;" - 7B.

После «\x» считываются еще две шестнадцатеричные цифры (они могут быть записаны в нижнем или верхнем регистре). В режиме UTF-8, разрешается использование «\x<. >«, где содержимое скобок является строкой из шестнадцатеричных цифр. Она интерпретируется как символ UTF-8 character с кодом, совпадающим с данным шестнадцатеричным числом. Исходная шестнадцатеричная экранирующая последовательность, \xhh, совпадает с двухбайтным UTF-8 символом, если его значение превышает 127.

После «\0» считываются две восьмеричные цифры. Если в записи менее двух цифр, будут использованы все фактически присутствующие цифры. Таким образом, последовательность «\0\x\07» будет интерпретирована как два бинарных нуля, за которыми следует символ оповещения (звонок). В случае, если вы используете представление числа в восьмеричном коде, убедитесь, что за начальным нулем следуют две значащие цифры.

Обработка обратного слеша, за которым следует ненулевая цифра, несколько сложнее. Вне символьного класса PCRE воспринимает обратный слеш и следующие за ним цифры как десятичное число. Если полученное значение меньше десяти, либо если шаблон содержит по меньшей мере такое же количество предшествующих текущей позиции подмасок, вся конструкция интерпретируется как ссылка на подмаску. Более детальное описание будет приведено ниже при обсуждении механизма работы подмасок.

Внутри символьного класса, либо если полученное значение больше 9 и соответствующее количество предшествующих подмасок отсутствует, PCRE считывает до трех восьмеричных цифр, следующих за обратным слешем, и генерирует один байт из последних 8-ми значащих битов полученного значения. Все последующие цифры обозначают себя же. Например:

\040

еще один способ записи пробела

\40

то же самое в случае, если данной записи предшествует менее сорока подмасок

\7

всегда интерпретируется как ссылка на подмаску

\11

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

\011

всегда интерпретируется как символ табуляции

\0113

символ табуляции, за которым следует цифра «3»

\113

интерпретируется как символ с восьмеричным кодом 113 (так как ссылок на подмаски не может быть более чем 99)

\377

байт, всецело состоящий из единичных битов

\81

либо обратная ссылка, либо бинарный ноль, за которым следуют цифры «8» и «1»

Следует помнить, что восьмеричные значения, превышающие 100, следует писать без лидирующего нуля, так как читается не более трех восьмеричных цифр.

Все последовательности, определяющие однобайтное значение, могут встречаться как внутри, так и вне символьных классов. Кроме того, внутри символьного класса запись «\b» интерпретируется как символ возврата (‘backspace’, шестнадцатеричный код 08). Вне символьного класса она имеет другое значение (какое именно, описано ниже).

Определение формальных утверждений

Ещё одно использование обратного слеша — определение некоторых формальных утверждений, описывающих условия касательно месторасположения особых позиций в строке и совершенно не затрагивающих сами символы. Использование подмасок как более сложных формальных утверждений описано далее. Такими управляющими последовательностями являются:

\b

\B

не является границей слова

\A

начало данных (независимо от многострочного режима)

\Z

конец данных либо позиция перед последним переводом строки (независимо от многострочного режима)

\z

конец данных (независимо от многострочного режима)

\G

первая совпадающая позиция в строке

Описанные выше последовательности не могут встречаться в символьных классах (исключая комбинацию «\b«, которая внутри класса означает символ возврата ‘backspace’).

Границей слова считается такая позиция в строке, в которой из текущего и предыдущего символа только один соответствует \w или \W (т.е. один из них соответствует \w, а другой \W). Начало или конец строки также соответствуют границе слова в случае, если первый или, соответственно, последний символ совпадает с \w.

Специальные последовательности \A, \Z и \z отличаются от общеупотребляемых метасимволов начала строки ‘^‘ и конца строки ‘$‘ (описанных в разделе якоря первой части) тем, что они всегда совпадают либо в самом начале либо в самом конце строки. На них никак не влияют опции m (PCRE_MULTILINE) и D (PCRE_DOLLAR_ENDONLY). Разница между \Z и \z в том, что \Z соответствует позиции перед последним символом в случае, если последний символ — перевод строки, кроме самого конца строки. В то время, как \z соответствует исключительно концу данных.

Утверждение \G является истинным только в том случае, если текущая проверяемая позиция находится в начале совпадения, указанного параметром offset функции preg_match(). Она отличается от \A при ненулевом значении параметра offset.

\Q и \E могут быть использованы для игнорирования метасимволов регулярных выражений в шаблоне. Например: \w+\Q.$.\E$ совпадет с один или более символов, составляющих «слово»,за которыми следуют символы .$. и якорь в конце строки.

Последовательность \K может быть использована для сброса начала совпадения. Например, шаблон foo\Kbar совпадет с «foobar», но сообщит о том, что совпал только с «bar». Использование \K не мешает установке подмасок. Например, если шаблон (foo)\Kbar совпадет со строкой «foobar», первой подмаской все равно будет являться «foo».

POSIX нотация для символьных классов

Perl поддерживает нотацию POSIX для символьных классов. Это включает использование имен, заключенных в [: и :], в свою очередь заключенных в квадратные скобки. PCRE также поддерживает эту запись. Например, [01[:alpha:]%] совпадет с «0», «1», любым алфавитным символом или «%«. Поддерживаются следующие имена классов:

alnum буквы и цифры
alpha буквы
ascii символы с кодами 0 — 127
blank только пробел или символ табуляции
cntrl управляющие символы
digit десятичные цифры (то же самое, что и \d)
graph печатные символы, исключая пробел
lower строчные буквы
print печатные символы, включая пробел
punct печатные символы, исключая буквы и цифры
space пробельные символы(почти то же самое, что и \s)
upper прописные буквы
word символы «слова» (то же самое, что и \w)
xdigit шестнадцатеричные цифры

Класс пробельных символов (space) — это горизонтальная табуляция (HT, 9), перевод строки (LF, 10), вертикальная табуляция (VT, 11), разрыв страницы (FF, 12), возврат каретки (CR, 13) и пробел (32). Учтите, что этот список включает вертикальную табуляцию (VT, код 11). Это отличает «space» от \s, который не включает этот символ (для совместимости с Perl).

Название word — это расширение Perl, а blank — расширение GNU, начиная с версии Perl 5.8. Другое расширение Perl — это отрицание, которое указывается символом ^ после двоеточия. Например, [12[:^digit:]] совпадет с «1», «2», или с любой не-цифрой.

В режиме UTF-8, символы со значениями, превышающими 128, не совпадут ни с одним из символьных классов POSIX. Начиная с PHP 5.3.0 и libpcre 8.10 некоторые символьные классы изменены, чтобы использовать свойства символов Unicode, в этом случае упомянутое ограничение не применяется. Читайте руководство PCRE(3) для подробностей.

Подмаски

Подмаска — это часть регулярного выражения, которая участвует в поиске. Подмаска может выполнять несколько функций:

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

2) найденная в подмаске строка может вновь использоваться в регулярном выражении в качестве обратной ссылке (о них позже)

Подмаски в регулярном выражении выделяются скобками. В регулярном выражении может быть более чем одна подмаска, в этом случае они нумеруются слева направо.

Подмаски могут быть вложенными одна в другую.

При использовании функции preg_match_all возвращается массива, где в качестве первого элемента (с индексом 0) возвращается массив с найденными значениями строк. Если указаны подмаски, то в качестве второго элемента возвращаемого массива (с индексом 1) будет массив с найденными строками, соответствующими первой подмаске. Если используется две подмаски, то будет возвращён ещё один массив и так далее для каждой последующей подмаске.

Как мы помним из первой части, описывающий синтаксис регулярных выражений, скобки имеют и другое значение: или использовании оператора | (ИЛИ) они ограничивают варианты альтернатив друг от друга. Например, шаблон cat(aract|erpillar|) соответствует одному из слов «cat», «cataract» или «caterpillar». Без использования скобок он соответствовал бы строкам «cataract», «erpillar» или пустой строке.

То есть скобки выполняют одновременно две функции.

На самом деле выполнение одновременно двух функций не всегда удобно. Бывают случаи, когда необходима группировка альтернатив без захвата строки. В случае, если после открывающей круглой скобки следует «?:«, захват строки не происходит, и текущая подмаска не нумеруется. Например, если строка «the white queen» сопоставляется с шаблоном the ((?:red|white) (king|queen)), будут захвачены подстроки «white queen» и «queen», и они будут пронумерованы 1 и 2 соответственно. Максимальное количество захватывающих подмасок — 65535. Такие большие шаблоны могут не скомпилироваться, в зависимости от настроек libpcre.

В случае, если в незахватывающей подмаске необходимо указать дополнительные опции, можно воспользоваться удобным сокращением: символ, обозначающий устанавливаемую опцию помещается между «?» и «:«. Таким образом, следующие два шаблона

соответствуют одному и тому же набору строк. Поскольку альтернативные версии берутся слева направо, и установленные опции сохраняют своё действие до конца подмаски, опция, установленная в одной ветке, также имеет эффект во всех последующих ветках. Поэтому приведенные выше шаблоны совпадают как с «SUNDAY», так и с «Saturday».

Также можно использовать именованные подмаски с помощью синтаксиса (?P pattern). Эта подмаска будет индексирована в массиве совпадений кроме обычного числового индекса, еще и по имени name. В PHP 5.2.2 было добавлено два альтернативных синтаксиса: (? pattern) и (?’name’pattern).

Иногда бывает необходимо иметь несколько совпадений, исключающих друг друга. Обычно, каждое такое совпадение получает свой собственный номер, даже если шаблон позволяет совпасть только одному из них. Синтаксис (?| позволяет обойти это поведение и убрать дублирующиеся номера. Рассмотрим следующее регулярное выражение, сопоставленное со строкой Sunday:

Здесь Sun сохраняется в ссылке 2, тогда как ссылка 1 пуста. Если же совпадет Sat, то она будет помещена в ссылку 1, а ссылка 2 вообще не будет существовать. Использование (?| в шаблоне решает эту проблему:

В этом шаблоне обе подмаски Sun и Sat будут сохранены под номером 1.

Обратные ссылки в PHP

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

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

Однако, в случае, если следующее за обратным слешем число меньше 10, оно всегда интерпретируется как обратная ссылка, и приводит к ошибке только в том случае, если нет соответствующего числа открывающих скобок. Другими словами, открывающие скобки не обязаны предшествовать ссылке для чисел меньше 10. «Упреждающая обратная ссылка» может иметь смысл, если используется повторение и более поздняя подмаска участвует в ранней итерации. Более детальную информацию об обработке цифр после обратного слеша можно найти в разделе «Обратный слеш».

Обратная ссылка сопоставляется с частью строки, захваченной соответствующей подмаской, но не с самой подмаской. Таким образом шаблон (sens|respons)e and \1ibility соответствует «sense and sensibility», «response and responsibility», но не «sense and responsibility». В случае, если обратная ссылка обнаружена во время регистрозависимого поиска, то при сопоставлении обратной ссылки регистр также учитывается. Например, ((?i)rah)\s+\1 соответствует «rah rah» и «RAH RAH», но не «RAH rah», хотя сама подмаска сопоставляется без учета регистра.

На одну и ту же подмаску может быть несколько ссылок. Если подмаска не участвовала в сопоставлении, то сопоставление со ссылкой на нее всегда терпит неудачу. Например, шаблон (a|(bc))\2 терпит неудачу, если находит соответствие с «a» раньше, чем с «bc». Поскольку может быть до 99 обратных ссылок, все цифры, следующие за обратным слешем, рассматриваются как часть потенциальной обратной ссылки. Если за ссылкой должна следовать цифра, необходимо использовать ограничитель. В случае, если указан флаг x (PCRE_EXTENDED), ограничителем может быть любой пробельный символ. В противном случае можно использовать пустой комментарий.

Ссылка на подмаску, внутри которой она расположена, всегда терпит неудачу, если это первое сопоставление текущей подмаски. Например, шаблон (a\1) не соответствует ни одной строке. Но все же такие ссылки бывают полезны в повторяющихся подмасках. Например, шаблон (a|b\1)+ совпадает с любым количеством «a», «aba», «ababaa». При каждой итерации подмаски обратная ссылка соответствует той части строки, которая была захвачена при предыдущей итерации. Чтобы такая конструкция работала, шаблон должен быть построен так, чтобы при первой итерации сопоставление с обратной ссылкой не производилось. Этого можно достичь, используя альтернативы (как в предыдущем примере), либо квантификаторы с минимумом, равным нулю.

Начиная с PHP 5.2.2, управляющая последовательность \g может быть использована для абсолютных и относительных ссылок на подмаски. После этой последовательности должно быть указано беззнаковое или отрицательное число, при желании заключенное в фигурные скобки. Последовательности \1, \g1 и \g эквивалентны друг другу. Использование этого шаблона с беззнаковым числом поможет избежать двусмысленности, присущей числам после обратного слеша. Это также помогает отличить обратные ссылки от символов в восьмеричном формате, а также упрощает запись числового литерала сразу после обратной ссылки, например, \g<2>1.

Использование отрицательных чисел с \g полезно при использовании относительных ссылок. Например, (foo)(bar)\g соответствует «foobarbar», а (foo)(bar)\g соответствует «foobarfoo». Это также может быть полезно в длинных шаблонах, в качестве альтернативы отслеживания числа подмасок, на которые можно ссылаться в последующей части шаблона.

Указать обратную ссылку на именованную подмаску можно с помощью (?P=name) или, начиная с PHP 5.2.2, \k или \k’name‘. Кроме того, в PHP 5.2.4 была добавлена поддержка \k> и \g>, а в PHP 5.2.7 для \g и \g’name’.

К примеру, я хочу найти строки, состоящие из пяти любых, но одинаковых цифр, например, «11111», «22222» и так далее, в этом случае я могу написать следующее регулярное выражение:

Как мы рассмотрели чуть выше, экранирующая последовательность \d обозначает любую цифру. Для того, чтобы найденную строку можно было использовать в качестве обратной ссылке, мы заключаем эту часть регулярного выражения в круглые скобки. То есть получается, что мы создаём подмаску в регулярном выражении. Затем идёт обратный слэш \ с цифрой 1 — это и есть обратная ссылка. То есть, что бы ни было найдено в первой подмаске, его значение будет помещено в обратную ссылку \1. Затем ещё идут три таких же обратных ссылки. Получается что регулярное выражение ищет любую цифру, за которой ещё четыре раза идёт эта же самая цифра.

Для поиска возьмём строку:

даст следующий результат:

В первый элемент массива помещён массив с найденными строками из пяти цифр. Во второй элемент массив помещён массив, соответствующий подмаскам — то есть одиночным цифрам. Но взяты не любые одиночные цифры — совпавшие значения подмасок взяты только в тех случаях, когда весь шаблон совпал со строкой.

Рассмотрим более практический пример. Допустим мы хотим найти в HTML коде все пары тэгов: открывающий и закрывающий тэг, между которыми идёт какой-либо текст. Есть исключения (например,
, и так далее) — но не будем их рассматривать, чтобы не усложнять пример.

Тэг абзаца выглядит примерно так:

Тэг раздела страницы:

Как мы видим, в угловые скобки помещено название тэга, которое представляет собой одну или более маленьких букв. Закрывающим тэгом является эта же самая конструкция, с этим же самым названием тэга, но перед названием добавляется слэш /.

Любая буква в угловых скобках обозначается так:

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

Закрывающим тэгом будет обратная ссылка, содержащая найденное название тэга, помещённая между , то есть:

Поскольку в качестве разделителя используется слэш, то тот слэш, который означает «буквальный слэш» нужно экранировать, чтобы он потерял своё специальное значение и стал трактоваться как буквальный символ, получаем:

Составленное регулярное выражение будет соответствовать тэгам в следующем написании:

Но нужно помнить, что между тэгами почти всегда есть какой-то текст. В качестве этого тэга может быть что угодно, кроме символа , поскольку этот символ означает завершение открывающего тэга, поэтому значение «пусто, либо пробел а затем любые символы кроме > любое количество раз» на языке регулярных выражений записывается так:

Помещаем эту конструкцию в ранее составленное регулярное выражение в то место, где могут быть атрибуты:

Функции PHP для поиска и замены по регулярному выражению

Рассмотренные ранее функции ищут строки по регулярному выражению (preg_match_all), либо проверяют, строку на соответствие регулярному выражению (preg_match). В случае, если нужно не просто найти строку, но и заменить её, используются следующие функции:

  • preg_filter — Производит поиск и замену по регулярному выражению
  • preg_replace_callback_array — Выполняет поиск и замену по регулярному выражению с использованием функций обратного вызова
  • preg_replace_callback — Выполняет поиск по регулярному выражению и замену с использованием callback-функции
  • preg_replace — Выполняет поиск и замену по регулярному выражению

В результате работы функции preg_replace, если найдены совпадения, возвращается новая версия subject, иначе subject возвращается нетронутым. Функция preg_filter() идентична функции preg_replace() за исключением того, что возвращает только те значения (возможно, преобразованные), в которых найдено совпадение. Подробнее о работе функций читайте по приведённым выше ссылкам.

Функция preg_replace_callback позволяет делать интеллектуальную замену. Её суть заключается в том, что не просто выполняется замена найденной строки, а вызывается функция, которой передаётся совпавшая строка, и эта функция уже и возвращает строку с заменой. Вместо элементарной замены, функция может, например, делать дополнительную проверку полученных данных и уже на основе принятого решения выполнять ту или иную замену. Можно установить счётчик и делать замену в каждом n-ной совпавшей строке — например, в каждой третьей или каждой десятой. Можно пронумеровать найденные строки и делать любые другие изменения, которые не ограничиваются обычным поиском и заменой на фиксированную строку.

Пример использование функции preg_replace_callback:

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

Пример моего реального недавнего использования функции preg_replace_callback на практике — добавления рекламы в каждый десятый комментарий — с её помощью очень легко реализовать подобную логику.

Другие функции PHP для работы с регулярными выражениями

  • preg_last_error — Возвращает код ошибки выполнения последнего регулярного выражения PCRE
  • preg_quote — Экранирует символы в регулярных выражениях
  • preg_split — Разбивает строку по регулярному выражению

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

Не используйте функцию preg_match(), если необходимо проверить наличие подстроки в заданной строке. Используйте для этого strpos() поскольку она выполнит эту задачу гораздо быстрее.

Если вам не нужна мощь регулярных выражений, то вместо preg_split вы можете выбрать более быстрые (хоть и простые) альтернативы наподобие explode() или str_split().

Регулярные выражения для чайников

Что такое регулярные выражения?

В народе: регэкспы, регулярки.

По-простому — это выражения для поиска и замены подстроки по шаблону.

В PHP используется название PCRE (Perl Compatible Regular Expressions —
перл совместимые регулярные выражения). В этой статье я постараюсь раскрыть
потенциал это мощного инструмента программиста. Не пытайтесь понять все сразу,
впитывайте порциями и приходите за добавкой.

Начнем

// наша строка для испытаний
$string = ‘abcdefghijklmnopqrstuvwxyz0123456789’ ;

Если нам нужно просто узнать есть ли шаблон ‘abc’ в строке $string
мы можем набросать такой код:

echo preg_match ( «/abc/» , $string ) ;
?>

Этот код выведет ‘1’. Потому что он нашел 1 (одно) вхождение шаблона в строке.
Если шаблон в строке не обнаружен, preg_match вернет 0. При нахождении первого вхождения,
функция сразу возвращает результат! Дальнейший поиск не продолжается (см. preg_match_all)

Нахождение начала строки

Теперь мы желаем узнать, начинается ли строка с ‘abc’.
Символ начала строки в регулярках — ‘^’ (caret — знак вставки).

// тест на начало строки
if ( preg_match ( «/^abc/» , $string ) )
<
// окей, строка начинается с абс
echo ‘The string begins with abc’ ;
>
else
<
echo ‘это фэйл’ ;
>
?>

Пример выведет:
The string begins with abc

Оборачивающие слэши — разделители, содержат регуряное выражение. Это могут быть любые парные символы,
например @regex@, #regex#, /regex/ и .т.п.

Символ ^ сразу после первого разделителя указывает что выражение начинается сначала строки и НИКАК иначе.

Что делать с регистром символов (строчные-прописные)

Перепишем код, чтобы он искал строку ‘ABC’:

Скрипт вернет:
Не думаю

Все потому что поиск регистро-зависимый. Шаблон ‘abc’ не тоже самое что ‘ABC’.
Чтобы найти оба варианта, нужно использовать модификатор. В регулярных выражениях
для этого применяется модификатор ‘i’, который нужно указать за закрывающим разделителем
регулярного выражения.

if ( preg_match ( «/^ABC/i» , $string ) ) <
echo ‘Совпадение, строка начинается с abc’ ;
> else <
echo ‘Не думаю’ ;
>
?>

Теперь скрипт найдет паттерн ‘abc’. Также теперь будут попадать под шаблон
строки вида abc, ABC, Abc, aBc, и т.п.

Позже будет рассказано подробнее о модификаторах.

Как указать в паттерне конец строки

Делается это также как и в случае с поиском начала строки.
Распространенная ошибка, допускаемя многими прогерами — использование символа $ для указания конца строки в шаблоне.
Это неверно, правильное решение — использовать утверждение \z. Посмотрите на этот код

Сниппет вернет true, потому что $ = \Z, что в свою очередь можно описать выражением (?=\z|\n\z).
Когда нам нужно получить в результате строку без «разделителей строк», $ не должен использоваться.
Также $ совпададет больше одного раза с модификатором /m, в противоположность \z. Изменим немного код,
удалим каретку (^) в начале паттерна и добавим \z в конце, также уберем зависимость от регистра модификатором /i.

// паттерн в конце строки?
if ( preg_match ( «/89 \z /i» , $string ) ) <
echo ‘Совпадение, строка заканчивается на 89’ ;
> else <
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
>> Совпадение, строка заканчивается на 89

Потому что мы определили конец строки 89. Вот так.

Мета символы

Ранее мы поэкспериментировали с простыми регулярками. Познакомились с кареткой (^) и долларом ($)/
Эти символы имееют особенное значение. Каретка (^) обозначает начало страки и доллар ($) — ее конец.
Такие символы в купе с остальными специальными называются мета символами (meta characters).

Список мета символов в регулярных выражениях:

Разберем все символы на примерах.
Если вам нужно составить шаблон в котором содержится такой символ, его необходимо экранировать (см. preg_quote)
Например шаблон: «1+1», нужно записать как-то так:

// образец
$string = ‘1+1=2’ ;

if ( preg_match ( «/^1 \+ 1/i» , $string ) ) <
// yep
echo ‘The string begins with 1+1’ ;
> else <
// nope
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
The string begins with 1+1

Потому что интерпретатор проигнорировал специальное значение символа «+», обозначенного символом экранирования «\» (бэкслэш).
Если бы мы не добавили экран к плюсу, то preg_match(«/^1+1/i», $string) не нашло бы совпадений с шаблоном.
Сам бэкслэш в свою очередь тоже нужно экранировать, если мы ищем именно этот символ «\\».

Что означают остальные мета символы

Квадратные скобки [ ] обозначают «строковой класс».

Символьный класс. Это просто набор символов, которые должны совпасть в искомой строке.
Они могут записываться индивидуально (по одному):

Или как диапазон, разделенный символом «-«:

// Ищем шаблон
echo preg_match ( «/b[aoiu]g/» , $string , $matches ) ;

Результат скрипта:
return 1

Потому что preg_match() нашел совпадение.
Этот код также найдет совпадение со строками ‘bag’ ‘bog’ ‘big’, но не с ‘beg’.
Диапазон символов [a-f] равнозначен такой записи [abcdef]. Словами формулируется так [от ‘a’ до ‘f’].
Еще раз повторю, выражения регистрозависимые, и [A-F] не тоже самое что и [a-f].

Мета символы не работыют внутри классов, поэтому их не нужно экранировать внутри квадратных скобок [. ].
Например класс [abcdef$] совпадет с символами a b c d e f $. Доллар ($) внутри класса — это простой бакс знак доллара без какого либо специального мета-свойства.

Есть правда исключения из правил:
Одна из полезных функций регулярных выражений — возможность указать шаблон НЕ совпадающий с диапазоном символов.
Чтобы это сделать, нужно использовать каретку (^) первым символом класса.
Найдем любые символы, кроме «b»:

// осуществляем поиск
preg_match ( «/[^b]/» , $string , $matches ) ;

// выведем все совпадения в цикле foreach
foreach ( $matches as $key => $value ) <
echo $key . ‘ -> ‘ . $value ;
>
?>

Результат скрипта:
0 -> a

Здесь preg_match() нашел первое совпадение с шаблоном /[^b]/.
Изменим скрипт и используем preg_match_all() для нахождения всех вхождений соответствующих шаблону /[^b]/.

// ищем ВСЕ совпадения
preg_match_all ( «/[^b]/» , $string , $matches ) ;

// выведем все совпадения в цикле foreach
foreach ( $matches [ 0 ] as $value ) <
echo $value ;
>
?>

Результат скрипта:
acefghijklmnopqrstuvwxyz0123456789

Выведет все символы, которые НЕ совпадают с шаблоном «b».

Так мы можем отфильтровать все цифры в строке:

// все символы не являющиеся цифрами от 0 до 9
preg_match_all ( «/[^0-9]/» , $string , $matches ) ;

foreach ( $matches [ 0 ] as $value ) <
echo $value ;
>
?>

Результат скрипта:
abcefghijklmnopqrstuvwxyz

Шаблон [^0-9] расшифровывается как все НЕ включая цифры от 0 до 9.

Продолжаете слушать нашу радиостанцию?
Тогда продолжим.

Метасимвол Бэкслэш (\).

Основное значение — экранирование других метасимволов.

// create a string
$string = ‘This is a [templateVar]’ ;

// try to match our pattern
preg_match_all ( «/[ \[ \] ]/» , $string , $matches ) ;

// loop through the matches with foreach
foreach ( $matches [ 0 ] as $value ) <
echo $value ;
>
?>

Здесь мы хотели найти все символы []. Без экранирования шаблон выглядел бы так — «/[[]]/»,
но мы добавили бэеслэши к скобкам [], чтобы отменить их мета-статус.
Также, к примеру, поступим с путем к файлу.
c:\dir\file.php
В паттерне будем использовать разделитель «\\».

Бэкслэш также ортодоксально используется в строках для указания специальных последовательностей: \n, \r и др.

Еще он неймспейсы разделяет!

Следующий символ «.» (точка) ака «полный стоп».

`Точка` совпадает с любым символом кроме символов разрыва строки \r или \n.
С помощью точки мы можем найти любой одиночный символ, за исключением разрыва строки.
Чтобы точка также совпадала с переводом каретки и разрывом строки, можно использовать флаг /s.

Ищем одиночный символ

$string = ‘sex at noon taxes’ ;

echo preg_match ( «/s.x/» , $string , $matches ) ;
?>

Результат скрипта:
1

Да, да preg_match() нашел одно совпадение. Пример также сработает с sax, six, sox, sux, и s x, но не совпадет с «stix».

Теперь попробуем найти \n.

// create a string
$string = ‘sex’ . » \n » . ‘at’ . » \n » . ‘noon’ . » \n » . ‘taxes’ . » \n » ;

// echo the string
echo nl2br ( $string ) ;

// look for a match
echo preg_match_all ( «/ \s /» , $string , $matches ) ;

Результат скрипта:
sex
at
noon
taxes
4

preg_match_all() нашел 4 совпадения разрыва строки «\n» потому что мы использовали флаг \s. Подробнее про флаге в разделе Спец Последовательностей..

Следующий волшебный символ — звездочка (*) asterisk
Совпадает с НОЛем и/или БОЛЕЕ вхождений шаблона, находящегося перед звездочкой.
* означает опциональный шаблон — допускается что символы могут быть, а могут и отсутствовать в строке.
Так шаблон .* совпадает с любым количеством любых символов. Пример:

// create a string
$string = ‘php’ ;

// look for a match
echo preg_match ( «/ph*p/» , $string , $matches ) ;

Результат скрипта:
1

Нашлось одно совпадение. В примере это один символ «h».
Пример также совпадет также со строкой «pp» (ноль символов «h»), и «phhhp» (три символа «h»).

Добрались до мета символа символа «+»

Плюс почти тоже самое что и звездочка, за исключением того что плюс совпадает с ОДНИМ и БОЛЬШЕ символом.
Так в примере звездочка «*» совпала со строкой ‘pp’, с плюсом «+» такое не пройдет.

// create a string
$string = ‘pp’ ;

// look for a match
echo preg_match ( «/ph+p/» , $string , $matches ) ;

Результат скрипта:

Потому что ни одного символа «h».

Следубщий пациент
Мета символ «?»

Знак вопроса совпадет с НУЛЕМ или ОДНИМ вхождением символа или регулярным выражением,
указанным сразу перед ним. Полезен для указания опциональных символов (которых может и не быть).

Например, телефонный номер в Австралии: 1234-5678.

// create a string
$string = ‘12345678’ ;

// look for a match
echo preg_match ( «/1234-?5678/» , $string , $matches ) ;

Результат скрипта:
1

Потому что -? совпал 0 раз с символом «-«. Изменение строки на «1234-5678» выдаст тот же результат.

Фигурные скобки <>

Указывает на количество совпавших символов или их интервал.
Например, за фразой PHP должно следовать ТОЧНО ТРИ цифры:

// create a string
$string = ‘PHP123’ ;

// look for a match
echo preg_match ( «/PHP[0-9]<3>/» , $string , $matches ) ;

Результат скрипта:
1

Шаблон PHP 0-9(цифры от 0 до 9) <3>(три раза) совпал.

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

Бэкслэш (\) используется для спец. последовательностей:

* \d — любая цифра (тоже самое что и [0-9])
* \D — любая НЕ цифра ([^0-9])
* \s — все «недосимволы» — пробелы, переводы строки, табуляция ([ \t\n\r\f\v])
* \S — все НЕ «недосимволы» ([^ \t\n\r\f\v])
* \w — все альфа-цифровые символы (буквенно-числовые) ([a-zA-Z0-9_])
* \W — все НЕ альфа-цифровые символы ([^a-zA-Z0-9_])

Итак, используя последофательности (флаги) мы можем сократить наши регулярные выражения
и улучшить их читабельность.

// match our pattern containing a special sequence
preg_match_all ( «/[ \w ]/» , $string , $matches ) ;

// loop through the matches with foreach
foreach ( $matches [ 0 ] as $value ) <
echo $value ;
>
?>

Результат скрипта:
abcefghijklmnopqrstuvwxyz0123456789

Мы нашли (preg_match_all) все цифры и буквы (\w) класса ( [] ).

На следующем примере мы можем убедиться, что строка не содержит чисел.

// create a string
$string = ‘2 bad for perl’ ;

// echo our string
if ( preg_match ( «/^ \d /» , $string ) ) <
echo ‘String begins with a number’ ;
> else <
echo ‘String does not begin with a number’ ;
>
?>

Метасимвол «.» (Точка, полный стоп)

Совпадает один раз с любым символом (кроме разрыва строки)

// create a string
$string = ‘abcdefghijklmnopqrstuvwxyz0123456789’ ;

// try to match any character
if ( preg_match ( «/./» , $string ) ) <
echo ‘The string contains at least on character’ ;
> else <
echo ‘String does not contain anything’ ;
>
?>

Результат скрипта:
The string contains at least on character

Конечно, код содержит хотябы один символ.

Ранее была рассмотрена проблема нахождения символа разрыва строки, потому что «.» не совпадает с таким символом (\n).
Здесь нам на помощь придет флаг \s. Он найдет любой пробельный символ (недосимвол).

Для примера используем \n.

// create a string
$string = ‘sex’ . » \n » . ‘at’ . » \n » . ‘noon’ . » \n » . ‘taxes’ . » \n » ;

// echo the string
echo nl2br ( $string ) ;

// look for a match
echo preg_match_all ( «/ \s /» , $string , $matches ) ;

Результат скрипта:
sex
at
noon
taxes
4

preg_match() нашел 4 совпадения перевода строки \n.

Теперь все вместе, хором

Более сложные выражения.
Рассмотрим оператор OR (ИЛИ).
В регулярных выражениях это символ «|» (труба, канал).

Настало время показательного «Hello World» скрипта.

// a simple string
$string = «This is a Hello World script» ;

// try to match the patterns This OR That OR There
echo preg_match ( «/^(This|That|There)/» , $string ) ;
?>

Усложним задачу: попытаемся найти одновременно Hello или Jello в строке.

// a simple string
$string = «This is a Hello World script» ;

// try to match the patterns Jello or Hello
if ( ! preg_match ( «/(Je|He)llo/» , $string ) ) <
echo ‘Pattern not found’ ;
> else <
echo ‘pattern found’ ;
>
?>

Хотя шаблон совпал, мы не видим какую имеено сроку мы нашли.
Для возвращения найденных результатов в preg_match добавляется третий параметр (&$matches):

// a simple string
$string = «This is a Hello World script» ;

// try to match the patterns Jello or Hello
// put the matches in a variable called matches
preg_match ( «/(Je|He)llo/» , $string , $matches ) ;

// loop through the array of matches and print them
foreach ( $matches as $key => $value ) <
echo $key . ‘->’ . $value . ‘
‘ ;
>
?>

Элемент массив $matches[0] содержит всю совпавшую подстроку (всегда), в примере — Hello.
Последующие элементы содержат последовательно вхождения субпаттернов «()».
$matches[1] совпадает с первым субпатерном. В примере — (Je|He)

Модификаторы и утверждения

Модификаторы изменяют поведения шаблонов регулярных выражений.

i — регистронезависимый (Ignore Case, case insensitive)
U — нежадный поиск (Make search ungreedy)
s — включая перевод строки (Includes New line)
m — мультистрока (Multiple lines)
x — Extended for comments and whitespace
e — Enables evaluation of replacement as PHP code. (preg_replace only)
S — Extra analysis of pattern

b — граница слова (Word Boundry)
B — НЕ граница слова (Not a word boundary)
A — начало шаблона (Start of subject)
Z — конец шаблона или разрыв строки (End of subject or newline at end)
z — конец шаблона (End of subject)
G — первая совпавшая позиция в шаблоне (First matching position in subject)
?>

Простой пример модификатора «i»

// create a string
$string = ‘abcdefghijklmnopqrstuvwxyz0123456789’ ;

// try to match our pattern
if ( preg_match ( «/^ABC/i» , $string ) ) <
echo ‘Совпадение, строка начинается с abc’ ;
> else <
echo ‘Не думаю’ ;
>
?>
?>

Использование модификатора «s»

/*** create a string with new line characters ***/
$string = ‘sex’ . » \n » . ‘at’ . » \n » . ‘noon’ . » \n » . ‘taxes’ . » \n » ;

/*** look for a match */
echo preg_match ( «/sex.at.noon/» , $string , $matches ) ;

Результат скрипта:

«.» не находит символы разрыва строки, добавим модификатор «s»
чтобы это исправить

/*** create a string with new line characters ***/
$string = ‘sex’ . » \n » . ‘at’ . » \n » . ‘noon’ . » \n » . ‘taxes’ . » \n » ;

/*** look for a match using s modifier ***/
echo preg_match ( «/sex.at.noon/s» , $string , $matches ) ;
?>
?>

Результат скрипта:
1

Разрывы строк позволяют нам использовать модификатор «m».
Это улично-магический модификатор. Он принимает строку за однострочнкую с символом разрыва на конце,
даже если в строке на самом деле больше символов разрыва (мультистрока).
Т.е. если в строке нет символов разрыва строк, этот модификатор ничего не значит.

// create a string
$string = ‘sex’ . » \n » . ‘at’ . » \n » . ‘noon’ . » \n » . ‘taxes’ . » \n » ;

// look for a match
if ( preg_match ( «/^noon/im» , $string ) ) <
echo ‘Pattern Found’ ;
> else <
echo ‘Pattern not found’ ;
>
?>

Результат скрипта:
Pattern Found

Конечно регулярное выражение найдет совпадение.
Все что следует после первого символа разрыва строки отбрасывается из-за модификатора «m».

В примере используюся вместе модификаторы «i» и «m», их действие комбинируется.

«x» модификатор позволяет составлять регулярное выражение на нескольких строках,
что повышает его читабельность и позволяет добавлять комментарии внутри шаблона.

// create a string
$string = ‘sex’ . » \n » . ‘at’ . » \n » . ‘noon’ . » \n » . ‘taxes’ . » \n » ;

// create our regex using comments and store the regex
// in a variable to be used with preg_match
$regex = ‘
/ # opening double quote
^ # caret means beginning of the string
noon # the pattern to match
/imx
‘ ;

// look for a match
if ( preg_match ( $regex , $string ) ) <
echo ‘Pattern Found’ ;
> else <
echo ‘Pattern not found’ ;
>
?>

Код в пояснениях не нуждается, он просто демонстрирует как можно вставить комментарии и
написать выражение в несколько строк.

Модификатор «e»

Спец млжификатор, который изменяет выполнение сопоставления шаблону. Ниже будет выделена целая секция для его описания.

Модификатор «S»

Этот модификатор позволяет нам проанализировать строку до сопостовления с шаблонами,
которые не помечены якорями. Т.е. если шаблон не имеет начальной фиксированой позиции, как например:

Паттерн может успорить выполение шаблона в случае с множественными совпадениями.
В следующем примере появляется множественное вхождение шаблона, поэтому добавим «S».

// match our pattern containing a special sequence
preg_match_all ( «/[ \w ]/S» , $string , $matches ) ;

// loop through the matches with foreach
foreach ( $matches [ 0 ] as $value ) <
echo $value ;
>
?>

Результат скрипта:
abcefghijklmnopqrstuvwxyz01234567890

На практике модификатор используется достаточно редко.

Модификатор границы слова (word boundary) «\b»

Граница слова создается между двух «\b» модификаторов.
Это специальный «подпирающий тип модификаторов, которые позволяют указть ТОЧНОЕ совпадение.
Текст должен совпасть только с точным шаблоном заключенным в «\b»
Например, шаблон «cat» не совпадет с «catalog».

$string = ‘eregi will not be available in PHP 6’ ;

// ищем строку «lab»
if ( preg_match ( «/ \b lab \b /i» , $string ) ) <
// Совпадение
echo $string ;
> else <
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
Не думаю

Мы пытаемся найти совпадение с паттерном «lab», которое находится внутри строки в слове «available».
Из за использования границ слов, шаблон не совпал с подстрокой.
Давайте попробуем пример, не используя модификатора границ слов.

$string = ‘eregi will remain in the computer lab’ ;

// ищем строку «lab»
if ( preg_match ( «/ \b lab \b /i» , $string ) ) <
// Совпадение
echo $string ;
> else <
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
eregi will remain in the computer lab

Мы видим что совпадение произошло с целым словом «lab». (\blab\b).

Модификатор \B

Этот модификатор относится к предыдущем, но \B не ставит условия гранц слова, а наоборот
отрицает границу слов. Этот модификатор полезен, когда нужно найти что-нибудь внутри
текста, который находится внутри слова, но не в самом начале или конце фразы.

$string = ‘This lathe turns wood.’ ;

// match word boundary and non-word boundary
if ( preg_match ( «/ \B the \b /» , $string ) ) <
echo ‘Совпал шаблон «the».’ ;
> else <
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
>> Совпал шаблон «the».

Этот код сначала найдет паттерн «the». Потому что сначала указан модификатор «не граница слова»,
the находится внутри фразы и не снача ее, затем модификатор \b границы указывает что фраза должна
закончится на -the.

$string = ‘The quick brown fox jumps over the lazy dog.’ ;

// match word boundary and non-word boundary
if ( preg_match ( «/ \B the \b /» , $string ) ) <
echo ‘Совпал шаблон «the».’ ;
> else <
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
Не думаю

В этот раз мы ничего не нашли, потому что «the» стоит на границе слова, а мы использовали модификатор \B.

Последний модификатор — \U

По умолчанию, PCRE «жадный» — это не значит что они съедят вашу печеньку,
а означает что шаблон совпадет с наибольшим возможным количеством символов,
попадающих под этот шаблон.

Чтобы отключить такую «жадность» регулярных выражений
— используем ограничитель «?», например «(.*?)»
— используем модификатор «\U».

Новичкам желательно использовать этот модификатор по-умолчанию, чтобы не возникало конфузов.

$string = ‘foobar foo—bar fubar’ ;

// try to match the pattern
if ( preg_match ( «/foo(.*)bar/U» , $string ) ) <
echo ‘Совпадение’ ;
> else <
echo ‘Не думаю’ ;
>

Результат скрипта:
Совпадение

Другой пример — дан кусок html

Попытаемся найти все ссылки выражением preg_match_all(«/.*/s», $string),
код вернет всю искомую строку вместо трех ссылок. Добавив Нежадный модификатор, все три ссылки поотдельности.

Вычисление с preg_replace

Приветствуем на сцене модификатор «e».

Этот модификатор вычисляет заменяемый аргумент.
До этого мы не рассматривали preg_replace(), поэтому быстрый пример:

$string = ‘We will replace the word foo’ ;

// заменяем `for` на `bar`
$string = preg_replace ( «/foo/» , ‘bar’ , $string ) ;

Пример заменит в строке foo на bar. В таких простых заменах целесообразнее использовать функции обработки строк
str_replace(), которые быстрее справляются с простыми задачами, но имеют некоторые ограничения, например не поддерживают юникод.

// строка с шаблонными переменными
$string = ‘This is the <_FOO_>bought to you by <_BAR_>‘ ;

// создади массив со значениями переменных
$templateVars = [ «FOO» => «The PHP Way» , «BAR» => «PHPro.orG» ] ;

// заменяем и вычисляем
$string = preg_replace ( «/<_(.*?)_>/ime» , » \$ templateVars[‘$1’]» , $string ) ;

Без модификатора «е» скрипты выдаст результат:
This is a $template_vars[FOO] and this is a $template_vars[BAR]

С модификатором переменные вычислятся после замены:
This is the The PHP Way bought to you by PHPro.orG

Таким образом, модификатор «e» обладает потенциалом встроенного шаблонизатора.

Заглядывание вперед (Look Aheads)

Возможность регулярных выражений «заглянуть вперед» шаблона для определения дальнейших совпадений.
«Подглядывание вперед» бывает положительное и отрицательное

Рассмотрим сначала заглядывание вперед с отрицанием. Обозначается в шаблоне символами «?!».
Полезно при поиске шаблона, стоящего впереди от совпадения, которое нам нужно.

$string = ‘I live in the whitehouse’ ;

// try to match white not followed by house
if ( preg_match ( «/white+(?!house)/i» , $string ) ) <
// if we find the word white, not followed by house
echo ‘Совпадение’ ;
> else <
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
No match is found

Потому что слово «white» следует за словом «house».
Подадим блюдо под другим соусом:

$string = ‘I live in the white house’ ;

// try to match white not followed by house
if ( preg_match ( «/white+(?!house)/i» , $string ) ) <
// if we find the word white, not followed by house
echo ‘Совпадение’ ;
> else <
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
Совпадение

Есть совпадение, потому что слово «white» не следует сразу же за словом «house» (как в «whitehouse»)

Позитивное/положительное заглядывание вперед «?=»

$string = ‘This is an example eg: foo’ ;

// try to match eg followed by a colon
if ( preg_match ( «/eg+(?=:)/» , $string , $match ) ) <
print_r ( $match ) ;
> else <
echo ‘Нет совпадений’ ;
>
?>

Результат скрипта:
Array < [0]=>‘eg’ >

Код ищет паттерн «eg», стоящий перед «:» двоеточием.
Но что если нам нужно найти что-то до двоеточия, например дом из предудыщего примера.
Для этого на помощь приходят «заглядывания назад».

Заглядывание назад (Look Behinds)

Позволяет просмотреть строку назад и определить наличие совпадений с шаблоном.
Также разделяется на положительное и отрицательное.
Положительное — записывается «?

$string = ‘I live in the whitehouse’ ;

// try to match house preceded by white
if ( preg_match ( «/(? , $string ) ) <
// if we find the word white, not followed by house
echo ‘Совпадение’ ;
> else <
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
Совпадение

Здесь мы нашли совпадение, потому что паттерн «house» сразу следует за паттерном «house».
Движок регулярных выражений «посмотрел назад» шаблона «house» и определил совпадение.

Если мы хотим, чтобы «house» НЕ следовал за словом «white»?
Используем отрицительное заглядывание назад — «?

/*** a simple string ***/
$string = ‘I live in the whitehouse’ ;

/*** try to match house preceded by white ***/
if ( preg_match ( «/(? , $string ) )
<
/*** if we find the word white, not followed by house ***/
echo ‘Совпадение’ ;
>
else
<
/*** if no match is found ***/
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
no match is found

Потому что отрицательное заглядывание не нашло шаблона «house» c шаблоном «white» в начале его.
Давайте поменяем цвет «дома», белым слишком девственный для правительственного здания.

$string = ‘I live in the bluehouse’ ;

// ищем `house` с непредшествующим `white`
if ( preg_match ( «/(? , $string ) ) <
/*** if we find the word white, not followed by house ***/
echo ‘Совпадение’ ;
> else <
/*** if no match is found ***/
echo ‘Не думаю’ ;
>
?>

Мы изменили «whitehouse» на «bluehouse» и теперь наша регулярка сработала, потому что
шаблон «white» не обнаружен перед «house».

По-умолчанию регулярки жадные, это значит что квантификаторы (какое слово страшное)
*, +, ? «пожирают» столько символов сколько могут.

/*** 4 x and 4 z chars ***/
$string = «xxxxzzzz» ;

/*** greedy regex ***/
preg_match ( «/^(.*)(z+)$/» , $string , $matches ) ;

/*** results ***/
echo $matches [ 1 ] ;
echo «
» ;
echo $matches [ 2 ] ;
?>

Первый паттерн (.*) совпал со всеми четыремя «x» и тремя из четырех символов «z».
Сработала жадность — шаблон забрал столько символов, сколько было в искомой строке.
Проще простого помочь перестать квантификаторам быть жадными, добавив «?» к квантификатору как в примере:

/*** string of characters ***/
$string = «xxxxzzzz» ;

/*** a non greedy match ***/
preg_match ( «/^(.*?)(z+)$/» , $string , $matches ) ;

/*** show the matches ***/
echo $matches [ 1 ] ;
echo «
» ;
echo $matches [ 2 ] ;
?>

Теперь $matches[1] содержит четыре «x» символа и $matches[2] четыре символа «z».
Потому что квантификатор «?» изменил поведение шаблона с «взять как можно БОЛЬШЕ» на «взять как можно МЕНЬШЕ».

Чтобы сделать нежадным весь шаблон, используем модификатор «U».

/*** string of characters ***/
$string = «xxxxzzzz» ;

/*** a non greedy match ***/
preg_match ( «/^(.*)(z+)$/U» , $string , $matches ) ;

/*** show the matches ***/
echo $matches [ 1 ] ;
echo «
» ;
echo $matches [ 2 ] ;
?>

Результат как в предыдущем примере.

Подводные камни c ? и U

Важно заметить, что модификатор «U» не только делает поиск нежадным, он инвертирует поведение жадности квантификатора «?».
Если использовался квантификатор «?» и одновременно модификатор «U», действие «?» будет инвертировано.

/*** string of characters ***/
$string = «xxxxzzzz» ;

/*** a non greedy match ***/
preg_match ( «/^(.*?)(z+)$/U» , $string , $matches ) ;

/*** show the matches ***/
echo $matches [ 1 ] ;
echo «
» ;
echo $matches [ 2 ] ;
?>

Результат скрипта:
xxxxzzz
Delimiters

В этом мане было рассмотрено много регулярок и все они разделялись слэшем «/».
Иногда нам нужно находить в шаблоне слэш и когда он одновременно является разделителем регуляного выражения,
нам придется экранировать каждый встречающийся слэш, что неудобно.

Поэтому в качестве разделителя можно взять любой символ, например #, @, ^ и т.п.

/*** get the host name from a url ***/
preg_match ( ‘#^(?:https://)?([^/]+)#i’ , «https://www.phpro.org/tutorials» , $matches ) ;

/*** show the host name ***/
echo $matches [ 1 ] ;
?>

Примеры

// the string to match against
$string = ‘The cat sat on the mat’ ;

// match the beginning of the string
echo preg_match ( «/^The/» , $string ) ;

// match the end of the string
// returns 1
echo preg_match ( «/mat \z /» , $string ) ;

// match anywhere in the string
// returns 0 as no match was found for dog.
echo preg_match ( «/dog/» , $string ) ;
?>

Поиск нескольких шаблонов

// the string to match against
$string = ‘The cat sat on the matthew’ ;

// matches the letter «a» followed by zero or more «t» characters
echo preg_match ( «/at*/» , $string ) ;

// matches the letter «a» followed by a «t» character that may or may not be present
echo preg_match ( «/at?/» , $string ) ;

// matches the letter «a» followed by one or more «t» characters
echo preg_match ( «/at+/» , $string ) ;

// matches a possible letter «e» followed by one of more «w» characters anchored to the end of the string
echo preg_match ( «/e?w+ \z /» , $string ) ;

// matches the letter «a» followed by exactly two «t» characters
echo preg_match ( «/at<2>/» , $string ) ;

// matches a possible letter «e» followed by exactly two «t» characters
echo preg_match ( «/e?t<2>/» , $string ) ;

// matches a possible letter «a» followed by exactly 2 to 6 «t» chars (att attt atttttt)
echo preg_match ( «/at<2,6>/» , $string ) ;

Запомните, preg_match() возвращает только 0 или 1, и останавливается после первого успешного нахождения шаблона.

Чтобы найти все совпадения — используйте preg_match_all().

Чит Шит

\w — Any “word” character (a-z 0-9 _)
\W — Any non “word” character
\s — Whitespace (space, tab CRLF)
\S — Any non whitepsace character
\d — Digits (0-9)
\D — Any non digit character
. — (Period) – Any character except newline

^ — Start of subject (or line in multiline mode)
$ — End of subject (or line in multiline mode)
[ — Start character class definition
] — End character class definition
| — Alternates, eg (a|b) matches a or b
( — Start subpattern
) — End subpattern
\ — Escape character

n- Zero or more of n
n+ — One or more of n
n? — Zero or one occurrences of n
— n occurrences exactly
— At least n occurrences
— Between n and m occurrences (inclusive)

i — Case Insensitive
m — Multiline mode — ^ and $ match start and end of lines
s — Dotall — . class includes newline
x — Extended– comments and whitespace
e — preg_replace only – enables evaluation of replacement as PHP code
S — Extra analysis of pattern
U — Pattern is ungreedy
u — Pattern is treated as UTF-8

\b — Word boundary
\B — Not a word boundary
\A — Start of subject
\Z — End of subject or newline at end
\z — End of subject
\G — First matching position in subject

(?=) — Positive look ahead assertion foo(?=bar) matches foo when followed by bar
(?!) — Negative look ahead assertion foo(?!bar) matches foo when not followed by bar
(? ) — Once-only subpatterns (?>\d+)bar Performance enhancing when bar not present
(?(x)) — Conditional subpatterns
(?(3)foo|fu)bar — Matches foo if 3rd subpattern has matched, fu if not
(?#) — Comment (?# Pattern does x y or z)

Дополнения от меня

Posix символьные классы

Дополнительные шорткуты для шаблонов. Могут применяться только внутри классов.
Пример для поиска числа с пробелами — preg_match(«@[[:space:]\d]+@», $string)

Внутренние модификаторы шаблонов

Модификаторы m, s, x, U, X, J могут использоваться внутри шаблона.
Например (?im) установит мультистроковой регистронезивисимый метод поиска для паттерна.
Отключить внутренние модификаторы можно перечислив их через дефис, например (?im-sx)

Пример:
шаблон (?i:foo) совпадет с «FoO»

Именованный «захват»

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

Записывается: (? ), (?’name’) или (?P ).
Раньше поддерживался только такой синтаксис: (?P ). [

preg_match ( ‘/Name: (.+), Age: ( \d +)/’ , $text , $matches ) ;
preg_match ( ‘/Name: (?P .+), Age: (?P \d +)/’ , $text , $matches ) ;
?>

Результат скрипта:
array(‘Name’ => ‘строка’, ‘Age’ => ‘число’)

Замена через callback-функцию

В php есть возможность указать функцию обратного вызова
для совпадений, если нам нужно проделать с ними необычные вещи.
Для этого используется preg_replace_callback.

\s * \w |’ ,
create_function (
‘$matches’ ,
‘return strtoupper($matches[0]);’
) ,
$line
) ;
?>

Данный код заменит все первые буквы в параграфах на заглавные.

В php >= 5.3 callback-функцию можно записать в сокращенном виде

\s * \w |’ ,
function ( $matches ) <
return strtoupper ( $matches [ 0 ] ) ;
> ,
$line
) ;
?>

Полезные регулярные выражения PHP

Полезные регулярные выражения PHP, которые обязательно пригодятся

Синтаксис регулярных выражений

Регулярное выражение Означает
foo Строка “foo”
^foo Строка начинается с “foo”
foo$ Строка заканчивается на “foo”
^foo$ «foo» встречается в строке только один раз
[abc] a, b, или c
[a-z] любой символ в нижнем регистре
[^A-Z] любой символ, не находящийся в верхнем регистре
(gif|jpg) Означает как «gif” так и “jpeg”
[a-z]+ Один или более символов нижнего регистра
[0-9.-] Любая цифра, точка или знак минус
^[a-zA-Z0-9_]<1,>$ Любое слово, хотя бы одна буква, число или _
([wx])([yz]) wy, wz, xy, или xz
(^A-Za-z0-9) Любой символ (не число и не буква)
([A-Z]<3>|[0-9]<4>) Означает три буквы или 4 цифры

PHP-функции для регулярных выражений

Функция Описание
preg_match() Функция preg_match() ищет строку по заданному шаблону, возвращает true, если строка находится и false, в остальных случаях
preg_match_all() Функция preg_match_all() находит все вхождения строки, заданной по шаблону
preg_replace() Функция preg_replace(), действует по тому же принципу, что и ereg_replace(), за исключением того, что регулярные выражения можно использовать как для задания шаблона поиска, так и для строки, на которую следует заменить, найденное значение.
preg_split() Функция preg_split(), действует так же как split(), за исключением того, что регулярное выражение можно использовать в качестве параметра для шаблона поиска.
preg_grep() Функция preg_grep() ищет все элементы входного массива, возвращая все элементы, соответствующие шаблону регулярного выражения.
preg_quote() Экранирует символы регулярного выражения

Проверка номера телефона

Регулярка проверяет соответствие формату +7 (999) 999-99-99

Проверка доменного имени

Проверяем, является ли строка правильным доменным именем

Подсветка слова в тексте

Это очень полезное регулярное выражение, с его помощью вы можете найти нужное слово и подсветить его. Особенно полезно для отображения результатов поиска.

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

Если вам когда-нибудь требовалось получить все картинки с веб-страницы, этот код должен быть Вы легко сможете создать загрузчик изображений с помощью возможностей cURL

Поиск XML/HTML тэгов

Эта простая функция, принимает два аргумента. Первый – это тэг, который вам нужно найти, и второй – это переменная, содержащая XML или HTML. Повторюсь, эту функцию очень удобно использовать вместе с cURL.

Поиск XHTML/XML тэгов с определенным значением атрибута

Эта функция очень похожа на предыдущую, за исключением того, что вы можете задать тегу нужный атрибут. Например, вы легко сможете найти

Поиск шестнадцатеричных значений цветов

Еще один полезный инструмент для веб-разработчика! Он позволяет вам находить/проверять шестнадцатеричные значение цвета.

Поиск заголовка статьи

Этот фрагмент кода найдет и выведет на экран текст, находящийся внутри тэгов , на html-странице.

Парсинг логов Apache

Большинство сайтов запущено на всем известном веб-сервере Apache. Если ваш

Замена двойных кавычек “умными” кавычками

Если вы любитель типографики, вам понравится это регулярное выражение, заменяющее обычные двойные кавычки, на “умные кавычки”. Похожее регулярное выражение используется в wordpress в контенте страницы.

WordPress: Использование регулярного выражения для получения картинок из записи

Поскольку многие из вас являются пользователями WordPress, вам возможно пригодится код, который позволяет получить все картинки, из текста статьи, и вывести их.

Для того, чтобы использовать этот код, просто вставьте его в любой файл вашей темы.

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

Написание регулярных выражений

В учебнике JavaScript подробно рассматривалось написание регулярных выражений. Синтаксис регулярок практически совпадает в JavaScript и PHP. Повторять здесь всё это ещё раз нет смысла. Если Вы не изучали эту тему то Вам нужно с ней ознакомиться. В частности, Вам нужно изучить эти темы:

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

Конечно написание регулярных выражений в JavaScript и PHP имеет отличия. В PHP оно более сложное и имеет дополнительные возможности. Но они сложнее, чем обычные регулярные выражения и не рассматриваются в этом учебнике. Кроме того, многие термины отличаются. Например флаги называются модификаторами. Однако допустимо использование разных терминов и в этом не будет ошибки. В PHP нет флага g , потому что нужное количество совпадений указывается в функциях. Есть одно отличие, которое нужно учитывать. В PHP регулярное выражение — это строка и она пишется в кавычках.

Поиск подстроки

Функция preg_match() ищет подстроку с использованием регулярного выражения. Возвращает 1, если есть хотя бы одно совпадение, 0 если совпадений нет, false при возникновении ошибки. Эта функция находит только первое совпадение.

preg_match (RegExp, строка, результат, флаг, смещение)

RegExp — регулярное выражение

строка — строка в которой производится поиск

результат — массив, в который записывается найденная подстрока.

флаг — если указать значение PREG_OFFSET_CAPTURE, то в результат добавится позиция первого символа найденной подстроки

смещение — позволяет искать не с начала строки, а с указанной позиции

Обязательны первые два параметра

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

Найдём в строке слово «задача» в разных падежах:

Если в функции preg_match() использовать флаг, то массив с результатом становится двухмерным. В нём будет подстрока и её позиция. Добавим флаг в функцию:

Обратите внимание, если в строке есть русский текст, то позиция подстроки определяется неправильно. Это происходит потому, что русские символы занимают больше одного байта. Подробнее об этом сказано теме о строках. В PHP есть функции для работы с регулярными выражениями в многобайтных кодировках. Они работают по-другому, но позволяют выполнить все основные действия.

Функция preg_match_all() выполняет те же действия, но находит все совпадения. Параметры те же самые. Найдём все вхождения слова «задача» в строке:

Замена подстроки

Функция preg_replace() находит подстроку по регулярному выражению и заменяет её на другую. Возвращает строку с изменениями.

preg_replace (RegExp, новая подстрока, строка, число замен, цифра)

RegExp — регулярное выражение

новая подстрока — строка на которую заменяется найденная подстрока

строка — строка в которой производится замена

число замен — максимально разрешённое количество замен. Дальнейшие замены производится не будут. Значение -1 означает, что количество не ограничено. Необязательный параметр

цифра — позволяет указать переменную, в которую будет записано количество произведённых замен

Уберём нумерацию из текста:

Найденную подстроку можно вставить в новую подстроку. Ссылка на неё пишется так: $0 . В том месте, где должна быть найденная подстрока, нужно указать этот код. Он пишется прямо внутри новой подстроки. Для примера добавим к числам указание того, что это пиксели:

Найденную строку можно вставлять по частям. Для этого паттерн нужно разделить на части. Каждая часть должна быть в скобках. Эти части называются подмаски. Чтобы вставить первую часть, нужно написать: $1 , чтобы вставить вторую часть — $2 и так далее. Поменяем запятую на точку в дробных числах:

Иногда бывает нужно сразу после кода подмаски написать число. Тогда два числа сливаются. В этой ситуации код подмаски можно написать с использованием фигурных скобок.

В функции preg_replace() вместо начальной строки можно указать массив. Замена будет произведена во всех его элементах. Функция вернёт массив с изменениями.

Разделение строки

Функция preg_split() делит строку на части по разделителю, указанному в регулярном выражении. Возвращает массив из частей строки.

preg_split (RegExp, строка, число элементов, флаги)

RegExp — регулярное выражение, определяющее разделитель

строка — строка, которая разделяется

число элементов — позволяет указать максимальное количество элементов в массиве. Когда достигается это количество, вся оствшаяся часть строки помещается в последний элемент массива. Значения NULL, 0, -1 указывают, что количество элементов не ограничено (по умолчанию)

флаги — флаги, определяющие работу функции

Возможны следующие флаги:

PREG_SPLIT_NO_EMPTY — не добавляет в массив пустые значения

PREG_SPLIT_DELIM_CAPTURE — часть регулярного выражения можно поместить в скобки. Подсткора, соответствующая этой части будет добавлена в массив.

PREG_SPLIT_OFFSET_CAPTURE — в массив добавляются позиции найденных разделителей

Если флагов несколько, между ними ставится оператор |

Разделим текст на предложения. Разделителями будут знаки препинания, которые ставятся в конце предложений:

В данном примере точка является разделителем. Она есть в конце строки. После этой точки в массив добавится пустое значение. Чтобы этого не было я добавил в функцию нужный флаг.

Коприрование материалов сайта возможно только с согласия администрации

Шпаргалка по регулярным выражениям

Квантификаторы

Аналог Пример Описание
? a? одно или ноль вхождений «а»
+ a+ одно или более вхождений «а»
* a* ноль или более вхождений «а»

Модификаторы

Символ «минус» (-) меред модификатором (за исключением U) создаёт его отрицание.

Описание
g глобальный поиск (обрабатываются все совпадения с шаблоном поиска)
i игнорировать регистр
m многострочный поиск. Поясню: по умолчанию текст это одна строка, с модификатором есть отдельные строки, а значит ^ — начало строки в тексте, $ — конец строки в тексте.
s текст воспринимается как одна строка, спец символ «точка» (.) будет вкючать и перевод строки
u используется кодировка UTF-8
U инвертировать жадность
x игнорировать все неэкранированные пробельные и перечисленные в классе символы

Спецсимволы

Аналог Описание
() подмаска, вложенное выражение
[] групповой символ
количество вхождений от «a» до «b»
| логическое «или», в случае с односимвольными альтернативами используйте []
\ экранирование спец символа
. любой сивол, кроме перевода строки
\d [0-9] десятичная цифра
\D [^\d] любой символ, кроме десятичной цифры
\f конец (разрыв) страницы
\n перевод строки
\pL буква в кодировке UTF-8 при использовании модификатора u
\r возврат каретки
\s [ \t\v\r\n\f] пробельный символ
\S [^\s] любой символ, кроме промельного
\t табуляция
\w [0-9a-z_] любая цифра, буква или знак подчеркивания
\W [^\w] любой символ, кроме цифры, буквы или знака подчеркивания
\v вертикальная табуляция

Спецсимволы внутри символьного класса

Пример Описание
^ [^da] отрицание, любой символ кроме «d» или «a»
[a-z] интервал, любой симво от «a» до «z»

Позиция внутри строки

Пример Соответствие Описание
^ ^a aaa aaa начало строки
$ a$ aaa aaa конец строки
\A \Aa aaa aaa
aaa aaa
начало текста
\z a\z aaa aaa
aaa aaa
конец текста
\b a\b
\ba
aaa aaa
aaa aaa
граница слова, утверждение: предыдущий символ словесный, а следующий — нет, либо наоборот
\B \Ba\B aaa aaa отсутствие границы слова
\G \Ga aaa aaa Предыдущий успешный поиск, поиск остановился на 4-й позиции — там, где не нашлось a

Скачать в PDF, PNG.

Якоря

Якоря в регулярных выражениях указывают на начало или конец чего-либо. Например, строки или слова. Они представлены определенными символами. К примеру, шаблон, соответствующий строке, начинающейся с цифры, должен иметь следующий вид:

Здесь символ ^ обозначает начало строки. Без него шаблон соответствовал бы любой строке, содержащей цифру.

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

Символьные классы в регулярных выражениях соответствуют сразу некоторому набору символов. Например, \d соответствует любой цифре от 0 до 9 включительно, \w соответствует буквам и цифрам, а \W — всем символам, кроме букв и цифр. Шаблон, идентифицирующий буквы, цифры и пробел, выглядит так:

POSIX

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

Утверждения

Поначалу практически у всех возникают трудности с пониманием утверждений, однако познакомившись с ними ближе, вы будете использовать их довольно часто. Утверждения предоставляют способ сказать: «я хочу найти в этом документе каждое слово, включающее букву “q”, за которой не следует “werty”».

Приведенный выше код начинается с поиска любых символов, кроме пробела ( [^\s]* ), за которыми следует q . Затем парсер достигает «смотрящего вперед» утверждения. Это автоматически делает предшествующий элемент (символ, группу или символьный класс) условным — он будет соответствовать шаблону, только если утверждение верно. В нашем случае, утверждение является отрицательным ( ?! ), т. е. оно будет верным, если то, что в нем ищется, не будет найдено.

Итак, парсер проверяет несколько следующих символов по предложенному шаблону ( werty ). Если они найдены, то утверждение ложно, а значит символ q будет «проигнорирован», т. е. не будет соответствовать шаблону. Если же werty не найдено, то утверждение верно, и с q все в порядке. Затем продолжается поиск любых символов, кроме пробела ( [^\s]* ).

Кванторы

Кванторы позволяют определить часть шаблона, которая должна повторяться несколько раз подряд. Например, если вы хотите выяснить, содержит ли документ строку из от 10 до 20 (включительно) букв «a», то можно использовать этот шаблон:

По умолчанию кванторы — «жадные». Поэтому квантор + , означающий «один или больше раз», будет соответствовать максимально возможному значению. Иногда это вызывает проблемы, и тогда вы можете сказать квантору перестать быть жадным (стать «ленивым»), используя специальный модификатор. Посмотрите на этот код:

Этот шаблон соответствует тексту, заключенному в двойные кавычки. Однако, ваша исходная строка может быть вроде этой:

Приведенный выше шаблон найдет в этой строке вот такую подстроку:

Он оказался слишком жадным, захватив наибольший кусок текста, который смог.

Этот шаблон также соответствует любым символам, заключенным в двойные кавычки. Но ленивая версия (обратите внимание на модификатор ? ) ищет наименьшее из возможных вхождений, и поэтому найдет каждую подстроку в двойных кавычках по отдельности:

Экранирование в регулярных выражениях

Регулярные выражения используют некоторые символы для обозначения различных частей шаблона. Однако, возникает проблема, если вам нужно найти один из таких символов в строке, как обычный символ. Точка, к примеру, в регулярном выражении обозначает «любой символ, кроме переноса строки». Если вам нужно найти точку в строке, вы не можете просто использовать « . » в качестве шаблона — это приведет к нахождению практически всего. Итак, вам необходимо сообщить парсеру, что эта точка должна считаться обычной точкой, а не «любым символом». Это делается с помощью знака экранирования.

Знак экранирования, предшествующий символу вроде точки, заставляет парсер игнорировать его функцию и считать обычным символом. Есть несколько символов, требующих такого экранирования в большинстве шаблонов и языков. Вы можете найти их в правом нижнем углу шпаргалки («Мета-символы»).

Шаблон для нахождения точки таков:

Другие специальные символы в регулярных выражениях соответствуют необычным элементам в тексте. Переносы строки и табуляции, к примеру, могут быть набраны с клавиатуры, но вероятно собьют с толку языки программирования. Знак экранирования используется здесь для того, чтобы сообщить парсеру о необходимости считать следующий символ специальным, а не обычной буквой или цифрой.

Спецсимволы экранирования в регулярных выражениях

Выражение Соответствие
\ не соответствует ничему, только экранирует следующий за ним символ. Это нужно, если вы хотите ввести метасимволы !$()*+.<>?[\]^ <|>в качестве их буквальных значений.
\Q не соответствует ничему, только экранирует все символы вплоть до \E
\E не соответствует ничему, только прекращает экранирование, начатое \Q

Подстановка строк

Подстановка строк подробно описана в следующем параграфе «Группы и диапазоны», однако здесь следует упомянуть о существовании «пассивных» групп. Это группы, игнорируемые при подстановке, что очень полезно, если вы хотите использовать в шаблоне условие «или», но не хотите, чтобы эта группа принимала участие в подстановке.

Группы и диапазоны

Группы и диапазоны очень-очень полезны. Вероятно, проще будет начать с диапазонов. Они позволяют указать набор подходящих символов. Например, чтобы проверить, содержит ли строка шестнадцатеричные цифры (от 0 до 9 и от A до F), следует использовать такой диапазон:

Чтобы проверить обратное, используйте отрицательный диапазон, который в нашем случае подходит под любой символ, кроме цифр от 0 до 9 и букв от A до F:

Группы наиболее часто применяются, когда в шаблоне необходимо условие «или»; когда нужно сослаться на часть шаблона из другой его части; а также при подстановке строк.

Использовать «или» очень просто: следующий шаблон ищет «ab» или «bc»:

Если в регулярном выражении необходимо сослаться на какую-то из предшествующих групп, следует использовать \n , где вместо n подставить номер нужной группы. Вам может понадобиться шаблон, соответствующий буквам «aaa» или «bbb», за которыми следует число, а затем те же три буквы. Такой шаблон реализуется с помощью групп:

Первая часть шаблона ищет «aaa» или «bbb», объединяя найденные буквы в группу. За этим следует поиск одной или более цифр ( [0-9]+ ), и наконец \1 . Последняя часть шаблона ссылается на первую группу и ищет то же самое. Она ищет совпадение с текстом, уже найденным первой частью шаблона, а не соответствующее ему. Таким образом, «aaa123bbb» не будет удовлетворять вышеприведенному шаблону, так как \1 будет искать «aaa» после числа.

Одним из наиболее полезных инструментов в регулярных выражениях является подстановка строк. При замене текста можно сослаться на найденную группу, используя $n . Скажем, вы хотите выделить в тексте все слова «wish» жирным начертанием. Для этого вам следует использовать функцию замены по регулярному выражению, которая может выглядеть так:

Первым параметром будет примерно такой шаблон (возможно вам понадобятся несколько дополнительных символов для этой конкретной функции):

Он найдет любые вхождения слова «wish» вместе с предыдущим и следующим символами, если только это не буквы или цифры. Тогда ваша подстановка может быть такой:

Ею будет заменена вся найденная по шаблону строка. Мы начинаем замену с первого найденного символа (который не буква и не цифра), отмечая его $1 . Без этого мы бы просто удалили этот символ из текста. То же касается конца подстановки ( $3 ). В середину мы добавили HTML тег для жирного начертания (разумеется, вместо него вы можете использовать CSS или ), выделив им вторую группу, найденную по шаблону ( $2 ).

Модификаторы шаблонов

Модификаторы шаблонов используются в нескольких языках, в частности, в Perl. Они позволяют изменить работу парсера. Например, модификатор i заставляет парсер игнорировать регистры.

Регулярные выражения в Perl обрамляются одним и тем же символом в начале и в конце. Это может быть любой символ (чаще используется «/»), и выглядит все таким образом:

Модификаторы добавляются в конец этой строки, вот так:

Мета-символы

Наконец, последняя часть таблицы содержит мета-символы. Это символы, имеющие специальное значение в регулярных выражениях. Так что если вы хотите использовать один из них как обычный символ, то его необходимо экранировать. Для проверки наличия скобки в тексте, используется такой шаблон:

Шпаргалка представляет собой общее руководство по шаблонам регулярных выражений без учета специфики какого-либо языка. Она представлена в виде таблицы, помещающейся на одном печатном листе формата A4. Создана под лицензией Creative Commons на базе шпаргалки, автором которой является Dave Child. Скачать в PDF, PNG.

Мастер Йода рекомендует:  По пунктам что нужно знать о бэкенде новичку в веб-разработке
Добавить комментарий