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

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

Правила составление шаблона (pattern)

Границы шаблона должны обозначаться определенными символами, часто используют "/", но я предпочитаю использовать "#" потому, что от обилия прямых/обратных слешей может в глазах зарябить, а "решетки" обычно больше нигде не используются. Итак: "#ТутТелоРегулярногоВыражения#"

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

#^/catalog/([A-Za-z0-9_\-\.]+)/([A-Za-z0-9_\-\.]+)\.html.*#

Это выражение предназначено для получения параметров в строке URL. В начале строки идет спецсимвол "^" - это означает начало строки. Далее идет "/catalog/" - тут нет спецсимволов, это просто текст, который должен содержатся в строке. Затем встретили круглые скобки, т.е. дошли до первого подвыражения. В квадратных скобках обозначаются множество символов, которые могут быть в строке в этом месте. Знак "-" означает перечисление. Знак "\" экранирует специальные символы. Таким образом, в первом подвыражении у нас могут идти БОЛЬШИЕ и маленькие буквы латинского алфавита, цифры от 0 до 9, знак подчеркивания, тире и точка. Тире и точка - это спецсимволы, но здесь они экранированы, поэтому здесь это просто символы. После квадратных скобок идет знак "+" - это значит предыдущий символ (а у нас это множество символов заданное в квадратных скобках) может идти 1 или больше раз. Затем идет "/" - это просто символ, и аналогичное второе подвыражение. Затем идет "\.html", что означает текст ".html". А затем спец символы ".*" точка означает любой символ, а звездочка любое количество предыдущего символа. Т.е. после ".html" может идти все что угодно.

Указание количества, квантификаторы

Выше мы уже рассмотрели такие символы, указывающие количество предыдущих символов, как + и *. Приведем все возможности указания количества:

{X} , где Х это число повторений, пример: [0-9]{5}, это значит что здесь должно быть 5 цифр
{X,Y} , где X минимальное количество, Y - максимальное количество повторений. Пример [0-9]{1,2} - 1 или 2 цифры. [0-9]{,2} -0, 1 или 2 цифры. [0-9]{2,} - 2 и более цифр
* любое количество символов (включая 0 символов)
+ 1 и более символов
? 1 или 0 символов

Спецсимволы

\ экранирование спецсимвола
\\ обратный слеш
| Метасимвол выбора (или или)
^ Метасимвол начала строки
$ Метасимвол конца строки
\n Символ перевода строки (шестнадцатеричный код 0x0A)
\r Символ возврата каретки (шестнадцатеричный код 0x0D)
\t Символ табуляции (шестнадцатеричный код 0x09)
. Точка. Любой символ.

Для некоторых групп символов есть специальные сокращения:

\d Цифра (0-9), вместо [0-9]
\D Не цифра (любой символ кроме символов 0-9)
\s Пустой символ (обычно пробел и символ табуляции)
\S Непустой символ (все, кроме символов, определяемых метасимволом \s)
\w "Словарный" символ (символ, который используется в словах. Обычно все буквы, все цифры и знак подчеркивания ('_'))
\W Все, кроме символов, определяемых метасимволом \w

"Жадность"

Рассмотрим понятие жадности регулярного выражения. Например есть строка:

"сейчас будет ссылка <a href="#">ссылка1</a>, и еще <a href="#">ссылка2</a>, итого 2 ссылки."

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

#(<a.+</a>)#

Читаем: подвыражение:

<a любой символ 1 или больше </a>

Вроди все верно, подвыражение подходит под:

<a href="#">ссылка1</a>

Но оно также подходит под:

<a href="#">ссылка1</a>, и еще <a href="#">ссылка2</a>

- его то мы и получим, т.к. регулярные выражения по умолчанию "жадные". Снять жадность можно с помощью модификатора "U", вот так:

#(<a.+</a>)#U

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

После регулярного выражения могут идти модификаторы: "#ТутТелоРегулярногоВыражения#ТутМодификаторы" Виды модификаторов:

i Включает режим case-insensitive, т.е. большие и маленькие буквы в выражении не различаются.
m Указывает на то, что текст, по которому ведется поиск, должен рассматриваться как состоящий из нескольких строк. По умолчанию механизм регулярных выражений рассматривает текст как одну строку вне зависимости от того, чем она является на самом деле. Соответственно метасимволы '^' и '$' указывают на начало и конец всего текста. Если же этот модификатор указан, то они будут указывать соответственно на начало и конец каждой строки текста.
s По умолчанию метасимвол '.' не включает в свое определение символ перевода строки. Указание этого модификатора снимает это ограничение.
U Снимает жадность регулярного выражения
u Включает работу регулярных выражений с кириллицей в UTF-8, иначе работает не корректно.

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

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

preg_match

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


preg_match ($pattern,$subject); 
//вернет:
//0 - соответствие не найдено
//1 - соответствие найдено
//false - произошла ошибка

preg_match_all

Выполняет глобальный поиск шаблона в строке:


$res = array();
preg_match_all ($pattern,$subject,$res); 

Возвращает количество найденных вхождений шаблона (которое может быть и нулем) либо FALSE, если во время выполнения возникли какие-либо ошибки. В переменную $res попадет результат поиска в виде массива: [0] содержит массив полных вхождений шаблона, элемент [1] содержит массив вхождений первой подмаски, и так далее. Для удобства работы с регулярными выражениями я создал страницу, где в режиме online можно поработать с функцией preg_match_all

preg_replace

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


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

Каждое значение может быть строкой или массивом, в случае, если $subject массив - возвращается массив, иначе строка

preg_split

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


preg_split ( string $pattern , string $subject [, int $limit = -1 [, int $flags = 0 ]] );

Возвращает массив, состоящий из подстрок заданной строки subject, которая разбита по границам, соответствующим шаблону pattern.

Комментарии:

Maks

25.01.2015 01:30:10

Спасибо! Грамотно разжевал

Алекс

05.01.2016 02:05:43

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

andrei

26.01.2016 16:04:24

Полезно, спасибо. Но тем не менее не могу применить на практике.
Для редиректа 301 с http://www.domain.com на http://domain.com в файле .htaccess должен быть следующий код:

RewriteCond %{HTTP_HOST} ^www.domain\.com$ [NC]
RewriteRule ^(.*)$ http://domain.com/$1 [R=301,L]

Непонятно:
1. Почему в www.domain\.com вторая точка экранирована, а первая нет, равно как и точка в http://domain.com ?

2. В RewriteRule
- для чего (.*) - как я понял это означает "все что угодно"
- что такое 1 после $ ?

Максим

26.01.2016 18:29:02

andrei, очень хорошие вопросы, отвечаю:

1. точка это означает любой символ, в том числе и точку, поэтому пример рабочий, но правильнее экранировать все точки.

2. Это нужно для подстановки полного адреса, покажу на примере адреса этой страницы:
http://max22.ru/php/php-reg/
если мы наберем http://www.max22.ru/php/php-reg/, то сработает указанное вами правило,
$1 - это кусок который попал в первую подстановку, в примере первая подстановка (.*), т.е. туда попадет весь путь: "php/php-reg/", и редирект будет на адрес без www но с полным путем: "http://max22.ru/php/php-reg/"
Если опустить $1, то будет переброс на главную страницу.

PS статься по теме: http://max22.ru/server/htaccess/

andrei

26.01.2016 18:51:11

Максим, спасибо.
1. С Ваших слов я правильно понимаю, что неэкранированная точка в www.domain\.com приведет к тому, что например строка wwwфdomain.com попадет под это условие и будет перенаправлена?
2. Если я правильно понял, .* - это в Перле Wild Card и в Вашем примере она принимает значение www. Но почему тогда (.*) стоит ПЕРЕД http://domain.com/$, в то время как в Вашем примере www вставляется между http:// и domain.com?

3. На этой странице выше сказано, что $ - это конец строки. Мой вопрос был что означает цифра 1 после символа конца строки?

andrei

26.01.2016 18:56:50

PS статься по теме: http://max22.ru/server/htaccess/ - на эту статью меня и привел Гугл, когда я спроси его про файл .htaccess.
И к ней у меня тоже вопрос.
Я уже видел много примеров редирект-кода в этом файле, но у Вас впервые увидел этот код заключенным в теги <IfModule mod_rewrite.c></IfModule> - это что, необязательные теги, или в других примерах их опускали для простоты?

Максим

26.01.2016 19:06:40

andrei,
1. Да, верно, wwwфdomain.com попадает под правило
2,3. В строке RewriteRule ^(.*)$ http://domain.com/$1 [R=301,L]
"^(.*)$" - это шаблон, где $ обозначает конец строки, и с этим шаблоном будет сравниваться адрес без хоста, т.е. "php/php-reg/"
а "http://domain.com/$1" - это строка подстановки, где $1 является переменной, куда будет записано значение попавшее в шаблон.

<IfModule mod_rewrite.c> код внутри тега будет работать, если установлен модуль апача mod_rewrite. Если апач без этого модуля (я не встречал такого примера в живую) и не написать данное условие, то сайт упадет с ошибкой 500

andrei

26.01.2016 19:26:42

1. строка подстановки - это частный случай строки и, следовательно, ей должен предшествовать символ начала строки ^, а после нее должен быть символ конца строки $ - почему нет ни того ни другого?

2. Т.е. первая команда RewriteCond %{HTTP_HOST} ^www.domain\.com$ [NC] не только задает условие, но еще и отрезает от URL доменную часть, а то, что останется загружает в шаблон?

Максим

26.01.2016 19:40:53

1. Нет, строка подстановки это не регулярное выражение - просто срока.
2. Не отсекает.
{HTTP_HOST} сравнивает только хост (домен)
RewriteRule - сюда хост (домен) не попадает,

andrei

26.01.2016 19:50:14

ОК, Максим, понято, спасибо за Ваше время

Оставить комментарий:

Представьтесь пожалуйста:
Электронная почта:
Электронный адрес не публикуются
Текст сообщения:
Для подсветки кода, оборачивайте ваш код в теги <code></code>
Введите 5 цифр с картинки:

Рекомендую:

Поддержать проект:

бесполезная кнопка, которую еще никто не нажал:)
Нажали! Кнопку нажали уже 4 человека!!! Спасибо, очень мотивирует!