Главная | Контакты



Главная > Программирование > RegExp - регулярные выражения

Составление регулярных выражений (regexp) с примерами

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

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

1. Вид функции для поиска соответствий

Формат функции такой:

preg_match (патерн, строка для поиска, массив результатов);

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

Строка для поиска – любые данные, в которых мы будем что-то искать.

Массив результатов – необязательный параметр, нужен только, если нам надо что-то выделить при поиске. Если не указывать его, то при соответствии функция возвращает TRUE, иначе FALSE.

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

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

'/набор/модификаторы'

 

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

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

 

i - регистро-независимый поиск по строке. Регистр букв не учитывается, что строчные, что прописные становятся равнозначны.

примеры:
preg_match ('/upper/', 'UPPER CASE'); - вернёт FALSE
preg_match ('/upper/i', 'UPPER CASE'); - вернёт TRUE

 

m - достаточно эксцентричный модификатор, имеющий специфическое применение. По умолчанию установка в набор символов ^ или $ рассматривается как поиск ОТ начала или ДО конца ОДНОЙ СТРОКИ. Т.е. если строка для поиска форматированный текст с переносами и указаны признаки поиска от начала или до конца, то без этого модификатора поиск будет произведён только по первой строке данных, все остальные строки будут проигнорированы. Если в наборе нет конкретной привязки к началу или к концу строки, то использование этого модификатора не имеет смысла.

примеры:
preg_match ('/^fird.*/', 'first line
second line
fird line
fourth line'); - вернёт FALSE

preg_match ('/^fird.*/m', 'first line
second line
fird line
fourth line'); - вернёт TRUE

 

s - если установлен этот модификатор, то все точки в наборе соответствуют не только любому символу, но и символу новой строки.

примеры:
preg_match ('/test.test/', 'test@test'); - вернёт TRUE
preg_match ('/test.test/', 'test-test'); - вернёт TRUE
preg_match ('/test.test/', "test\ntest"); - вернёт FALSE

preg_match ('/test.test/s', 'test@test'); - вернёт TRUE
preg_match ('/test.test/s', 'test-test'); - вернёт TRUE
preg_match ('/test.test/s', "test\ntest"); - вернёт TRUE

 

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

примеры:
preg_match ('/t e s t/', 't e s t'); - вернёт TRUE
preg_match ('/t e s t/', 'test'); - вернёт FALSE

preg_match ('/t e s t/x', 't e s t'); - вернёт FALSE
preg_match ('/t e s t/x', 'test'); - вернёт TRUE
preg_match ('/t\ e\ s\ t/x', 'test'); - вернёт FALSE
preg_match ('/t\ e\ s\ t/x', 't e s t'); - вернёт TRUE

 

e - применим только к функции preg_replace() и заставляет эту функцию обрабатывать полученное значение как php скрипт, экранируя любые кавычки обратной косой чертой.

примеры:
Преобразование всех тегов в HTML документе в верхний регистр:
$html = '<select><option value="all">Everything</option></select>';
preg_replace ('/(<\/?)(\w+)([^>]*>)/e', "'\\1'.strtoupper('\\2').'\\3'", $html);

вернёт:

<SELECT><OPTION value=\"all\">Everything</OPTION></SELECT>

 

S - этот модификатор следует использовать для наборов, которые применимы многократно и ускоряет процесс поиска.

примеры:
preg_match_all ('/[\w]/', $string, $matches); – выполняется за 0.17 секунд
preg_match_all ('/[\w]/S', $string, $matches); – выполняется за 0.15 секунд

 

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

примеры:
preg_match ('/foo(.*)bar/', 'foobar foo–bar fubar'); – успокоится только по нахождению
preg_match ('/foo(.*)bar/U', 'foobar foo–bar fubar'); – будет достаточно и первого слова

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

 

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

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

И так, приступим. На самом деле в составлении регулярного выражения нет ничего сложного, главное понять, что к чему. Регулярное выражение указывается в кавычках, сам набор для поиска указывается между двумя косыми, после второй из которых идут модификаторы, '/набор условий/ модификаторы'. Поехали.

 

^ - этот символ имеет 2 значения, в зависимости от того, где он стоит. Если этот символ стоит в начале набора, он символизирует, что поиск соответствия нужно начинать с самого начала СТРОКИ (помните пример с модификатором m?), многие ошибочно считают, что с начала данных для поиска.

примеры:
'/^test/' найдёт слово test в "test it", но не найдёт его в "for test", потому что первое слово явно не test.
'/test/' найдёт слово test в обоих случаях, так как нет привязки к началу строки.

Если этот символ стоит внутри класса, то означает отрицание

примеры:
'/[^test]/' будет истинно для всего чего угодно, но только не test.
'/^[^test]/' а это означает, всё что угодно с начала строки, но только не test.

 

$ - этот символ (доллар) признак конца документа, если стоит в самом конце набора и не экранирован.

примеры:
'/^test$/' не найдёт слово test ни в "test it", ни в "for test", потому что стоит жёсткая привязка к концу и к началу строки. По этому выражению поиск будет удачным, если строка состоит из единственного слова test.
'/test$/' найдёт слово test в "for test", это конец документа и соблюдение нашего условия.

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

Теперь переходим к классам. Класс - это сложное условие, заключённое в квадратные скобки, которые вы уже видели раньше.

 

[] - обозначение сложного условия. Мы применяли ранее его для обозначения отрицания, но возможности его велики.

примеры:
[ABCD] будет истинно, если есть хоть одна их этих букв. Классы можно делать сквозными, то есть это же условие эквивалентно [A-D]. Заметьте, что знак <минус> внутри класса обозначает промежуток, если он стоит вне класса, он расценивается как элемент для поиска.

preg_match ('/[A-D]/', 'testB'); - вернёт TRUE, так же как и для testA, testC, testD или в любой другой строке, где есть A, B, C, D независимо от места их расположения в строке. Если добавить модификатор i, то мы так же сможем успешно искать и a, b, c, d.

[a-zA-Zа-яА-Я] класс, который будет истинной ко всем буквам.
[0-9] класс для всех цифр.

Но есть уже заранее предопределённые классы в php:

\w - все буквы
\d - все цифры. Ещё иногда обозначается [[:digit:]], но \d однозначнее приятнее выглядит
\W - отрицание класса букв, то есть все, что не буквы
\D - отрицание класса цифр
\s - пробел, знак табуляции, символ новой строки, в общем любой разделитель.
\S - под этот класс подходят все <видимые> символы.

Вы обратили внимание на обратную косую черту? А зря. Этот знак в начале чего-либо вызывает экранирование, то есть чтобы обозначить, что дальше после него что-то будет: как вы уже поняли, буквы экранировать не надо, а надо экранировать так называемые мета-символы. Неэкранированные мета-символы являются системными, будьте внимательны! То есть если мы напишем \[ это уже не будет означать начало класса, а просто поиск [.

Запомните, все классы работают по условию ИЛИ.

 

. - точка. Вы уже читали ранее в модификаторах, что точка - это любой символ, кроме символа новой строки без соответствующего модификатора.

примеры:
preg_match ('/a.cd/', 'azcd'); - вернёт TRUE, как и для любого "a*cd"

 

{} - это признак количества или квантатор. Квантатор символизирует количество предшествующего элемента. Может указывать на чёткое количество искомых элементов, либо может состоять из двух чисел, разделённых запятой.

примеры:
preg_match ('/a{4}/', 'a'); - вернёт FALSE
preg_match ('/a{4}/', 'aaaa'); - вернёт TRUE, но и для любого "aaaaaaaaaaaaaaaa", пока нет конкретной привязки к чему либо
preg_match ('/b{2,4}/', 'ab'); - вернёт FALSE, b должно быть от 2 до 4 по количеству
preg_match ('/^b{2,4}$/', 'bbb'); - вернёт TRUE, так как уже есть привязка к началу и концу строки, то "bbbbbbbbbbb" вернёт FALSE, и будет только истинно для строки с b в количестве от 2 до 4.
preg_match ('/^b{2,}$/', 'bbbbbbbbbbbbb'); - вернёт TRUE, так как не указано конечное количество и такой квантатор читается как не менее.

 

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

примеры:
preg_match ('/abc*d/', 'abcd'); - вернёт TRUE
preg_match ('/abc*d/', 'abcccccccccccccccccd'); - вернёт TRUE
preg_match ('/abc*d/', 'abd'); - вернёт TRUE, потому что "c" как бы присутствует в количестве 0.

 

+ - квантатор, который символизирует количество, не менее одного.

примеры:
preg_match ('/abc+d/', 'abcd'); - вернёт TRUE
preg_match ('/abc+d/', 'abcccccccccccccccccd'); - вернёт TRUE
preg_match ('/abc+d/', 'abd'); - вернёт FALSE, потому что "c" отсутствует.

 

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

 

| - символ, символизирующий о наличии нескольких возможных вариантов.

примеры:
preg_match ('/very nice|good/', 'very nice'); - вернёт TRUE
preg_match ('/very nice|good/', 'very good'); - вернёт TRUE
preg_match ('/very nice|good/', 'very cool'); - вернёт FALSE, потому что слово "cool" в альтернативах нет

 

? - символизирует о необязательном присутствии предшествующего элемента.

примеры:
preg_match ('/colou?r/', 'color'); - вернёт TRUE
preg_match ('/colou?r/', 'colour'); - вернёт TRUE
preg_match ('/colouu?r/', 'color'); - вернёт FALSE
preg_match ('/colouu?r/', 'colour'); - вернёт TRUE

 

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

примеры:
preg_match ('/colou?r\s(\w+)/', 'color black', $matches);
$matches[1]; - вернёт "black"
preg_match ('/\S+\s(\S+)\s\S+\s(\S+)/', 'name Vasya from Muhosransk', $matches);
$matches[1]; - вернёт "Vasya"
$matches[2]; - вернёт "Muhosransk"

3. Примеры использования

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

1. Считаем ссылки:

preg_match ('/<a href="([^"]+)">([^<]+)<\/a>/', '<a href="http://www.ptipti.ru">Сайт Pti_the_Leader</a>', $matches);

результат выполнения получим

Array (
[0] => <a href="http://www.ptipti.ru">Сайт Pti_the_Leader</a>
[1] => http://www.ptipti.ru
[2] => Сайт Pti_the_Leader
)

Как мы описали ссылку:

/<a href="([^"]+)">([^<]+)<\/a>/'

Теперь давайте разберём эту паттерну. Понятно, что ссылка - это тег и формат его мы тоже знаем

<a href="адрес">анкор</a>

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

<a href="(адрес)">(анкор)</a>

Уже есть начало. Как же нам описать адрес? Ведь в нём может быть http и косые, а может и не быть: В общем можно используя все полученные знания привлечь, чтобы составить огромный паттерн: но мы пойдём другим путём. Посмотрим на атрибут ссылки href и повнимательнее. Он заключён в кавычки, это всегда так: первую кавычку мы не трогаем, тоже понятно, и надо найти всё, что угодно до второй кавычки: то есть вторая кавычка - это стоп, говорящий, что всё значение найдено. Вот давайте и обозначим ссылку, что это всё, что угодно, кроме кавычки:

<a href="([^"]+)">(анкор)</a>

Вот мы создали класс [], в котором минимум один символ + и всё что угодно, кроме кавычки ^"

Как теперь описать анкор? \w+? А пробелы? Сделаем опять точно так же, анкор стоит между >< значит первый > мы от него и начинаем поиск и до <,

<a href="([^"]+)">([^<]+)</a>

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

2. Считывание данных.

Вернёмся к примеру из буферизации:

preg_match ('/\S+\s(\S+)\s\S+\s(\S+)/', , $matches);

рассмотрим наш паттерн '/\S+\s(\S+)\s\S+\s(\S+)/'

Не разделитель больше одного, разделитель, (не разделитель больше одного), то есть Vasya, разделитель, не разделитель больше одного, разделитель, (не разделитель больше одного), то есть Muhosransk. Этот паттерн не универсален и будет работать только максимум со строкой, в которой разделители будут ещё или знаки табуляции или знаки новой строки. А если к тому же разделителей будет несколько, и нужные нам данные будут стоять, к примеру, через двоеточие? Понятное дело, что этой паттерной мы уже данные не сможем считать. Давайте опять подумаем, нам нужно считать именно слова, значит будем использовать \w класс и его отрицание.

'/\w+\W+(\w+)\W+\w+\W+(\w+)/i'

Это более улучшенный вариант, который найдёт и Васю и его город проживания и в "name Vasya from Muhosransk", и в "name : Vasya from - Muhosransk", и даже в "name : $+Vasya+$ from - –==Muhosransk==–"

4. Заключение

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


Материал взят с сайта: http://www.ptipti.ru/%D1%81%D0%BE%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D1%80%D0%B5%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D1%85-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B9-regexp-%D1%81/
Главная > Программирование > RegExp - регулярные выражения