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

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

В основном работу регулярных выражений можно описать примерно следующим путем, регулярное выражение это метод сопоставления с образцом или согласующих моделей в строке. В PHP наиболее часто используется PCRE или «Perl Compatible Regular Expressions». Сегодня мы оставим простые методы поиска строк и будем работать с более сильным инструментом, которым многие пользуются но не знают как он работает. Здесь мы попытается декодировать бессмысленные иероглифы какими их все считают и сделаем это на примерах. Самая главная ошибка те кто изучает регулярные выражения это попытка понять все в один присест.

Начинаем изучение

Создайте у себя на тестовом сервере файл index.php и разместите в него код:

Немного модифицируем код и допишем функцию preg_match().

После запуска скрипта мы получим 1, а это значит что часть текста была найдена в строке $string (в PHP 1 и TRUE равные ответы).

Мы привили пример того как найти строку, но есть способ сделать это быстрее через стандартные функции php StrPos () и strstr ().

Указание начала строки в регулярном выражении

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

После выполнения кода вы увидите надпись «Эта строка начинается с abc», так как наша строка действительно начинается с букв «abc». Символ (^) дает нам поиск только по началу строки, но не по всей. Эта конструкция по умолчанию учитывает регистр.

Поиск подстроки в начале без учета регистра

Раньше мы использовали комбинацию if(preg_match(«/^ABC/», $string)), но эта комбинация выдала бы ошибочный результат, так как она учитывает регистр букв. Рассмотрим PHP код который не будет учитывать регистр букв при поиске.

Конструкция всего немного поменялась и был добавлен еще один модификатор i preg_match(«/^ABC/i«, $string) — case insensitive (регистронезависимый). После наших поправок скрипт будет отлично находить подстроку.

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

Во многом поиск строки по ее концовке похож на предыдущий пример. Все что необходимо это добавить \z к концу шаблона поиска.

Так как наша строка заканчивается на 89 и шаблон поиска соответствует концу строки, то результат будет «Конец строки равен 89».

Мета символы

Мы с вами уже использовали специальные символы такие как (^) и ($) эти символы, наряду с другими называют мета символами. Вот список мета символов которые также используются в регулярных выражениях:

. (Полная остановка)
^ (Carat) — начало строки
* (Asterix) — означает любое количество символов в строке, предшествующих «звездочке», в том числе и нулевое число символов.
+ (Plus) — указывает на то, что предыдущий символ или выражение встречается 1 или более раз. Играет ту же роль, что и символ «звездочка» (*), за исключением случая нулевого количества вхождений.
? (Question Mark) — означает, что предыдущий символ или регулярное выражение встречается 0 или 1 раз. В основном используется для поиска одиночных символов.
{ (Opening curly brace)
} (Closing curly brace) — {a,b} — количество вхождений предшествующего символа или подмаски от а до б. Если б не указан, считается, что верхней границы нет. Например, * — то же самое, что {0,}. ? — то же, что {0,1}. {5,7}5,6 или 7 повторений.
[ (Opening brace)
] (Closing brace) — предназначены для задания подмножества символов. Квадратные скобки, внутри регулярного выражения, считаются одним символом, который может принимать значения, перечисленные внутри этих скобок.
\ (Backslash) — служит для экранирования специальных символов, это означает, что экранированные символы должны интерпретироваться буквально, т.е. не как мета символы, а как простые символы.
| (Pipe) —  выполняет роль логического оператора «ИЛИ» в регулярных выражениях и служит для задания набора альтернатив ‘re(a|e)d’.
( (Opening parens)
) (Closing parens) — предназначены для выделения групп регулярных выражений. Они полезны при использовании с оператором «|» и при извлечении подстроки с помощью команды expr.

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

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

Рассмотрим что могут делать другие мета символы

Мы уже видели символ каретки ^ и доллар $? давайте посмотрим на другие, начиная с квадратных скобок []. Квадратые cкобки предназначены для поиска символов [abcdef] или диапазона символов [a-f]. Посмотрим на пример регулярного выражения:

Выражение вернет истину если в строке встречаются слова big, bog, bug, bag но не beg.

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

Давайте попробуем следующий скрипт:

Результатом работы скрипта будет вывод 0 -> a скрипт выводит символы до символа b.

Давайте попробуем немного модифицировать наш скрипт и использовать функцию preg_match_all().

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

Этот скрипт возвращает строку:
abcefghijklmnopqrstuvwxyz

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

Оставайтесь с нами, дальше еще интереснее

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

Результатом работы скрипта будет:

[]

Это потому что мы указали что хотим взять все символы которые соответствуют []. Для того чтобы выражение сработало правильно мы использовали косые черты, если вам надо чтобы косая черта расценивалась как простой символ, вам будет необходимо указать две косые черты \\, например для такого выражения c:\dir\file.php.

Рассмотрим работу с оператором точкой ( . ) на простом примере:

В результате мы получим 1, так как в нашей строке есть слово sex, это выражение также будет находить слова SOX, SUX и SX, но не будет находить Stix.

Давайте попробуем посчитать количество слов в строке при помощи регулярного выражения с точкой.

Код выше вернет это:
sex
at
noon
taxes
4

Сначала мы вывели строку, а оператор \n выставил переносы. Ниже мы видим число 4, это количество слов которое нашла функция preg_match_all ().

Давайте далее мы поработаем с мета символом ( * ). Этому оператору будет соответствовать любое количество любых символов, которые могут быть до оператора, а могут и не существовать. Посмотрим на пример ниже:

В результате мы получим 1 поскольку мы нашли 1 выражение которое соответствует выражению. Также верным будет выражение pp (без символов) и phhhp (с несколькими символами).

Если нам необходимо исключить пустой результат вида pp, то можно использовать мета символ ( + ). Посмотрим на примере:

Использование символа ( + ) работает похоже на ( * ), но плюс не учитывает пустое значение.

Наш следующий мета символ знак вопроса ( ? ), он означает что предыдущий символ может быть, а может и не быть. Примером может быть написание номера телефона, оба выражения будут истиной (1234-5678) и (12345678).

Аналогичный результат будет при использовании следующего кода:

Далее у нас есть фигурные скобки или {} метасимволы. Задают число вхождений предыдущего выражения или диапазона. Фигурные скобки обязательно должны экранироваться косой чертой «[0-9]\{5\}».
Выражение «[0-9]\{5\}» — в соответствует подстроке из пяти десятичных цифр (символов из диапазона от 0 до 9, включительно).

Далее мы будем использовать выражение в котором после текста «PHP» обязательно должны дополнятся ровно 3 цифрами.

Результатом регулярного выражения будет истина (1). Из регулярного выражения видно что оно должно начинаться текстом PHP и дополняться тремя цифрами от 0 до 9.

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

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

  • \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_]

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

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

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

Этот пример покажет что в строке вначале строит цифра 2.

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

Точка ( . ) означает любого символа, не менее одного, за исключением символа перевода строки (\n).

Попробуем использовать последовательность \s для получения количества слов в строке разделенной \n.

Результат выражения:

sex
at
noon
taxes
4

Подытожим наши знания

Начнем сочетать наши выражения в более сложный вид. Следующее выражение показывает что в строке должно быть одно из слов This или That или There.

Еще один интересный пример скрипта для определения начала слова.

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

Если вы все сделали правильно, то результатом выражения будет:

0->Hello
1->He

$matches[0] содержит полный текст шаблона выражения — Hello.
$matches[1] содержит первую часть шаблона выражения.

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

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

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

i — регистронезависимость.
U — инвертирует жадность. это значит, что шаблон совпадет с наибольшим возможным количеством символов, попадающих под этот шаблон.
s — если используется, то символ . соответствует и переводу строки \n. Иначе она ему не соответствует.
m — мультистрока (Multiple lines)
x — заставляет игнорировать все неэкранированные пробельные символы, если они не перечислены в символьном классе. Удобно, когда энтерами и пробелами вы хотите навести удобночитаемость в регулярке.
e — Если используется данный модификатор, preg_replace() после выполнения стандартных подстановок в заменяемой строке интерпретирует ее как PHP-код и использует результат для замены искомой строки. Одинарные и двойные кавычки, обратные слэши (\) NULL-символы будут проэкранированы обратными слэшами в подставляемых обратных ссылках. (Работает только с preg_replace).
S — в случае, если планируется многократно использовать шаблон, имеет смысл потратить немного больше времени на его анализ, чтобы уменьшить время его выполнения. В случае, если данный модификатор используется, проводится дополнительный анализ шаблона. В настоящем это имеет смысл только для «незаякоренных» шаблонов, не начинающихся с какого-либо определенного символа. Об этом чуть позднее.

Утверждения

b — Word Boundry (граница слова)
Граница слова создается между двух «\b» модификаторов.
Это специальный «подпирающий тип модификаторов, которые позволяют указть ТОЧНОЕ совпадение.
Текст должен совпасть только с точным шаблоном заключенным в «\b»
Например, шаблон «cat» не совпадет с «catalog».
B — Not a word boundary (не является границей слова)
Этот модификатор относится к предыдущем, но \B не ставит условия гранц слова, а наоборот отрицает границу слов. Этот модификатор полезен, когда нужно найти что-нибудь внутри текста, который находится внутри слова, но не в самом начале или конце фразы.
A — PCRE_ANCHORED
Если используется данный модификатор, соответствие шаблону будет достигаться только в том случае, если он «заякорен», т.е. соответствует началу строки, в которой производится поиск. Того же эффекта можно достичь подходящей конструкцией с вложенным шаблоном, которая является единственным способом реализации этого поведения в Perl.
Z — указание конца строки.
конец данных либо позиция перед последним переводом строки (независимо от многострочного режима).
z — указание конца строки.
конец данных (независимо от многострочного режима).
G — первая совпадающая позиция в строке.

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

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

Модификатор (i)

Если вы читали предыдущие части этого урока не будет никакого удивления, что данная конструкция посчитала похожими «ABC» и  с abc, потому что мы использовали модификатор регистронезависимости (i) .

Модификатор (s)

Продолжим изучение и рассмотрим модификатор (s). Если используется данный модификатор, то символ ( . ) соответствует и переводу строки \n. Иначе она ему не соответствует. Сначала мы попробуем пример без модификатора (s).

Как видим этот пример вернул ответ ( 0 ), для того чтобы  результат был положительный ( 1 ), а символ ( . ) учитывал \n, необходимо добавить в выражение модификатор ( s )? перестроим наш пример.

Приведенный выше код будет отображать число 1, так как строка по шаблону выражения была найдена.

Модификатор (m)

При добавления модификатора к строке, будет происходить интересная магия. Регулярное выражение будет воспринимать одну строку как несколько, если в ней стоит перенос \n. Для того чтобы было проще понять действие модификатора посмотрите на пример.

В данном примере мы при помощи мета символа ( ^ ) ищем слово noon в начале строки. Наша строка начинается с слова sex, а значит в обычном случае мы бы не нашли искомое слово. Так как в нашем примере все слова разделены \n и стоит модификатор ( m ), то каждое слово будет восприниматься как начало строки. Чтобы при поиске не учитывался регистр букв мы еще добавили модификатор ( i ). Если посмотрите внимательно на пример выше, то увидите что можно использовать несколько модификаторов рядом стоящих.

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

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

Рассмотрим пример множественного вхождения (совпадения):

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

Далее мы поработаем с границами слов \b, этот модификатор позволяет нам четко определить где начинается и заканчивается слово. Частая ошибка программистов в использовании этого модификатора для поиска вхождения. Поиск вхождения с \b вернет результат false. Рассмотрим на примере:

Искомое слово lab не было найдено в слове available из за использования \b в шаблоне. Для модификатора \b в поиске, слова cat и catalog будут разными словами.

Рассмотрим еще один пример поиска выражения:

Поиск удался!

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

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

Пример со словом которое начинается заданным вхождением

На примере вам должно быть понятно почему слово «the» не было найдено, все потому что мы при помощи регулярного выражения «/\Bthe\b/» указали что «the» это конец слова, но не целое слово.

Модификатор \U используется для инвертирования жадности.

Этот модификатор инвертирует жадность квантификаторов, таким образом они по умолчанию не жадные. Но становятся жадными, если за ними следует символ ?. Его также можно установить с помощью (?U) установки модификатора внутри шаблона или добавив знак вопроса после квантификатора (например, .*?).

Пример использования жадных и ленивых выражений из wikipedia

Выражение (<.*>) соответствует строке, содержащей несколько тегов HTML-разметки, целиком.
<p><b>wp-admin.com.ua</b> — уроки разработки сайтов и <i>cms wordpress</i> </p>
Чтобы выделить отдельные теги, можно применить ленивую версию этого выражения: (<.*?>) Ей соответствует не вся показанная выше строка, а отдельные теги (выделены цветом):
<p><b>wp-admin.com.ua</b> — уроки разработки сайтов и <i>cms wordpress</i></p>

Использование preg_replace

Думаю тут проще будет вам попробовать ввести представленный код и посмотреть на результат работы функции.

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

Рассмотрим более сложный пример замены при помощи функции preg_replace().

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

https://www.php.su/lessons/?lesson_17

https://www.skillz.ru/dev/php/article-Regulyarnye_vyrazheniya_dlya_chaynikov.html

https://www.phpro.org/tutorials/Introduction-to-PHP-Regex.html

https://www.compileonline.com/execute_php_online.php

Николаенко Максим

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


Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Шаблоны для WordPress
Самый лучший хостинг в Украине
Стабильный хостинг для Drupal