Что такое регулярные выражения и зачем они нужны? Если у нас есть текст, в котором мы что-то хотим поменять, то, без так называемого "регулярного поиска" не обойтись. Например, мы хотим проверить правильность передачи от пользователя нашему скрипту Email, либо хотим найти все ссылки на страничке и вывести их на печать, либо хотим заменить какое-то слово на что-то, вот тут-то и нужен регулярный поиск.
Чтобы понять, как ищется в тексте что-то, надо сначала определиться с местом, где мы будем искать что-то. То есть, надо понять и дать определение: строки, подстроки, текста, подтекста, слова, символа.
\n - это символ перевода каретки, он невидим в тексте.
Символ.
Символ - это одиночный знак в строке.
Есть печатные (те, что видны взгляду) и непечатные ( те, что взгляду не видны) символы.
Непечатные символы сами по себе состоят из нескольких символов, чтобы набрать такой символ, его надо предварять слешем:
Слово.
Слово - это последовательность всех печатных символов, ограниченных пробелом или [\n].
это_одно_слово
а_это_два\nслова
а_это три\nслова
а это четыре слова
Строка.
Строка - это последовательность любых символов, ограниченная [\n].
$stroka = "это одна строка \n это вторая строка \n это третья строка";
Подстрока.
Подстрока - это часть строки.
Текст.
Текст - это массив строк.
$stroka = "это одна строка \n это вторая строка \n это третья строка";
При записи $stroka в текстовый файл, вид файла будет такой:
это одна строка
это вторая строка
это третья строка
[\n] заменились на перевод каретки и остались лежать в конце каждой строки и стали невидимы.
Синтаксис строк.
Итак, строки отображаются двумя видами:
<?php
$str = "ха-ха";
$stroka = 'В тексте что-то написано $str';
// тогда $stroka = В тексте что-то написано $str
$stroka = "В тексте что-то написано $str";
// тогда $stroka = В тексте что-то написано ха-ха
?>
Итак, если строки ограничены двойными кавычками, тогда в них будет подстановка всех переменных, если одинарными строка воспринимается, как есть. То есть:
<?php
$str = '<font color="ff000">\ слеш перед кавычками и перед слешем не ставится \</font>';
?>
<?php
$str = "<font color=\"ff000\">\\ слеш ставится \\</font>";
?>
Строки наполняются печатными и непечатными символами. У печатных символов есть эквиваленты. Называется это ASCII символы. Создадим скрипт, чтобы это увидеть:
<?php
for ($i=10; $i<300; $i++){
// печатаем символы начиная с 10 до 300
echo"Номеру $i соответствует (ASCII &#$i;) символ: &#$i; <br>\n";
}
?>
Если Вы запустите этот скрипт, то будет вывод заменителей символов вида "
То есть, у всех печатных символов есть эквиваленты ASCII типа &#(номер);
Немного о метасимволах:
\" - двойная кавычка
\$ - знак доллара
\\ - обратный слеш
Эти символы, только в таком, виде будут обозначать самих себя в строке.
Другие метасимволы:
\ . | ( ) [ ] { } ? * + ^ - /
Все эти символы сами участвуют в механизме регулярного поиска, поэтому ко всем ним надо применять специальные методы, если они будут определять самих себя. В этом и есть сложность "Регулярного поиска" - в нем участвуют те символы, которые, может быть, нам придется искать в строках, используя в выражениях эти же символы.
Шаблон.
Чтобы в тексте что-то найти, надо составить регулярное выражение, которое состоит из ограничителей шаблона, самого шаблона и необязательных модификаторов:
/шаблон/модификаторы
Это и есть регулярное выражение, которое найдет в нашем тексте шаблон и вернет его нам. Вы видите, что сам шаблон ограничен прямыми слешами "/" - ограничители шаблона. Чтобы в шаблоне использовать этот прямой слеш, надо предварять его обратным, так как мы используем его в самом регулярном выражении. Тогда, шаблон будет:
/кино\/слова/модификаторы
сам шаблон ограничен "/"и в середине его мы поставили "\/", программа это поймет, как прямой слеш. То есть, в тексте, в этом случае, мы будем искать:
"кино/слова"
Опустим, пока, слово модификаторы и займемся самим шаблоном:
/шаблон/
Итак, вся мощь регулярных выражений заключается в подстановке в шаблон метасимволов, которые обозначают в нем те или иные действия, то есть являются управляющими структурами этого шаблона.
| - этот знак в шаблоне обозначает альтернативу, по типу: если этот знак не нашли, значит ищем другой.
/а|о/
этот шаблон будет искать "а", если не найдет, будет искать "о". То есть, такой шаблон ищет совпадения слева - направо, до первого совпадения, потом останавливается:
совпадет - "вина сливу" (нашлось 'а')
совпадет - "вину слово" (нашлось 'о')
не совпадет - "вину сливу"
^ - этот знак в шаблоне обозначает, чтобы в начале обязательно стояли следующие за ним символы.
/^в/
этот шаблон будет искать "в" и найдет, если этот знак будет стоять первым:
не совпадет - "кино слово" (нет 'в' в начале, нельзя)
совпадет - "вино слово" ('в' в начале)
$ - этот знак в шаблоне обозначает претензию "в конце", то есть символ говорит о том, чтобы в конце обязательно стояли, предшествующие ему символы.
/о$/
этот шаблон будет искать "о" и найдет, если этот знак будет стоять последним:
не совпадет - "вино слова" (нет 'о' в конце, нельзя)
совпадет - "вино слово" ('о' в конце)
* - этот знак в шаблоне обозначает количество совпадений, это числитель ноль или более раз
/а*/
этот шаблон будет искать "а" и найдет только в том случае, если "а" будет находиться в строке ноль или более раз. То есть, совпадет с любой строкой и вернет ее:
совпадет - "вино слова" (есть 'а')
совпадет - "вину сливу" (нет 'а', но все - равно совпадает)
+ - этот знак в шаблоне обозначает количество совпадений, это числитель 1 или более раз
/а+/
этот шаблон будет искать "а" и найдет, если "а" будет находиться 1 или более раз. То есть, если "а" нет, то совпадения не будет. Если будет хотя бы одна "а", или много "а", то будет совпадение:
совпадет - "вино слова" (есть 'а' один и более раз)
не совпадет - "вино слово" (нет 'а')
? - этот знак в шаблоне обозначает количество совпадений, это числитель 0 или 1 раз
/а?/
этот шаблон будет искать "а" и найдет только в том случае, если "a" будет находиться 0 или 1 раз. То есть, если "а" не будет больше одной:
не совпадет - "вино слава" (есть 'а', но больше 1 раза, нельзя)
совпадет - "вино слива" (есть 'а' один раз)
совпадет - "вину сливу" (нет 'а', но все - равно совпадет)
{ } - эти знаки в шаблоне обозначают сколько раз должно быть совпадение
? тоже самое, что и {0,1} - ноль или один раз
* тоже самое, что и {0, } - ноль или более раз
+ тоже самое, что и {1, } - один или более раз
То есть, {2,3} - должно быть два или три совпадения. Ставится после символа, который будем искать без пробелов и через запятую: {1,9} {0,35}, итд. Первая цифра обозначает минимум совпадений, последняя - максимум.
/a{2,3}/ - 'а' должно быть два или три раза
/a{1,2}/ - 'а' должно быть один или два раза
Подшаблон.
( ) - эти знаки в шаблоне обозначают ограничители подшаблона, которые можно создавать и в дальнейшем ссылаться на них.
/(^в)ин(а|о) слов(а$)/
В шаблоне мы сказали: в начале "в", потом буквы "а" или "о" должны следовать за "ин", потом пробел, потом "слов" и "а" в конце:
не совпадет - "кино слова" (нет в начале 'в', нельзя)
не совпадет - "вино слово" (нет 'а' в конце, нельзя)
не совпадет - "вину слово" (нет 'а' или 'о' после 'вин', нельзя)
совпадет - "вина слова" ( 'вина' совпало с 'а' (а|о) и 'а' в конце)
В шаблоне три подшаблона: (^в) (а|о) (а$).
Первый подшаблон (^в) - надо, чтобы "в" стояла в начале:
Второй подшаблон (а|о) - совпадет с буквами "а" или "о":
Третий подшаблон (а$) - надо чтобы "а" стояла в конце:
Все эти три подшаблона никак не влияют на сам шаблон
То есть, теперь у нас есть четыре объекта, к которым мы сможем обращаться: Сам шаблон и три подшаблона, которые находятся в самом шаблоне. На подшаблоны можно ссылаться в самом шаблоне. Ссылки на подшаблоны обозначаются в виде \\1, \\2, … \\99.
/(^в)ин(а|о) слов(\\2)$/
В этом случае, вы видите \\2 - это ссылка на второй подшаблон (считаются с места открывающейся скобки с 1 до 99). Вместо \\2 будет подставляться то, что уже нашлось во втором подшаблоне (о|а).
Теперь: в начале "в", затем идет "ин", потом следуют "а" или "о", потом пробел, потом "слов", а в конце то, что уже совпадет во втором шаблоне, то есть "а" или "о".
не совпадет - "кина слова" (нет 'в' в начале, нельзя)
не совпадет - "вино слова" (в слове 'вино' 'о', поэтому надо 'слово'- ссылка \\2)
совпадет - "вина слова" (в слове 'вина' 'а', поэтому 'слова' - ссылка \\2)
[ ] - эти знаки в шаблоне обозначают ограничители класса символов
Здесь метасимволами являются два знака '-' знак диапазона символов, и '^' меняет класс на его противоположность. [a-z] - только строчные буквы, [^a-z] - все кроме строчных букв.
/(^в)ин(а|о)[ ]{0,1}слов(\\2)$/
В этом шаблоне мы пишем: 'в' в начале, затем 'а' или 'о' после 'ин', затем пробел 0 или 1 раз, затем 'слов', в конце ссылка на второй подшаблон, в котором уже будет 'а' или 'о'.
совпадет - "вина слова" (в слове 'вина' 'а', поэтому 'слова' и есть пробел можно)
совпадет - "винослово" (в слове 'вино' 'о', поэтому 'слово' и нет пробела можно)
не совпадет - "вина слова" (между словами два пробела)
/(^в)ин(а|о)[^ ]слов(\\2)$/
не совпадет - "вина слова" (между словами пробел)
совпадет - "вина_слова" (в слове 'вина' 'а', поэтому 'слова' и нет пробела)
То есть, [^ ] - изменило на противоположное значение, теперь пробел нельзя.
[a-zA-Z] - все буквы
[^a-zA-Z] - все кроме букв
[0-9] - все цифры
[^0-9] - все кроме цифр
/(^[^0-9])ин(а|о)[ ]{1}слов(\\2)$/
Что мы сказали в этом шаблоне: (^[^0-9]) - в начале '^' должно быть все, кроме цифр '[^0-9]', затем 'а' или 'о' после 'ин', затем пробел один раз '[ ]{1}', затем 'слов', в конце ссылка на второй подшаблон '\\2', в котором уже будет 'а' или 'о'.
не совпадет - "винаслова" (между словами нет пробела)
не совпадет - "вина слова" (между словами два пробела)
совпадет - "вина слова" (нет цифр в начале и один пробел)
совпадет - "кина слова" (нет цифр в начале и один пробел)
Точка.
. - точка в шаблоне обозначает, что шаблон совпадет с любым символ строки, кроме [\n].
/./
то есть, этот шаблон совпадет с любыми символами, кроме знака [\n]:
совпадет - "абв" (выведет только 'а' 'б' 'в')
совпадет - "а\nб\nв" (выведет только 'а' 'б' 'в', [\n] не выведет)
Подстановка.
\ - обратный слеш в шаблоне обозначает подстановку.
/\./ - мы предварили точку обратным слешем и, теперь, наш шаблон будет искать точку, и совпадет только с ней в нашем тексте, а не со всеми символами, как было в последнем примере. То есть, обратный слеш служит для обозначения самих метасимволов, как обычных символов текста. Так же, все метасимволы надо предварять слешем для обозначения самих себя.
Подстановка метасимвола:
\\ \. \| \( \) \[ \] \{ \} \? \* \+ \^ \/ \# \!
Подстановка непечатного символа:
\a \e \f \n \r \t \cx - мы рассмотрели ранее
Подстановка печатного символа:
\xшш, где шш - одна или две шестнадцатеричные цифры
\шшш, где шшш - одна или три восьмеричные цифры
Подстановка ссылки на подшаблон
\шш, где шш - цифры от 1 до 99, ссылку на подшаблон мы рассмотрели выше
Подстановка класса символов
\d - любой цифровой символ [0-9]
\D - любой НЕ цифровой символ [^0-9]
\s - любой пробельный символ [\t\ \r\f\n]
\S - любой НЕ пробельный символ [^\t\ \r\f\n]
\w - любой алфавитно-цифровой символ [a-zA-Z0-9_]
\W - любой НЕ алфавитно-цифровой символ [^a-zA-Z0-9]
Кроме этого, классы символов можно обозначать так:
[[:alnum:]] - все алфавитно-цифровые символы [a-zA-Z0-9]
[[:alpha:]] - все алфавитные символы [a-zA-Z]
[[:blank:]] - символ табуляции и пробел [\t ]
[[:cntrl:]] - все управляющие символы
[[:digit:]] - все десятичные цифры [0-9]
[[:graph:]] - все печатные символы, за исключением пробела
[[:lower:]] - все строчные буквы [a-z]
[[:upper:]] - все прописные буквы [A-Z]
[[:print:]] - все печатные символы
[[:punct:]] - все знаки препинания [\.,;:-]
[[:space:]] - все пустые символы
[[:xdigit:]] - все шестнадцатиричные цифры
Если вы поставите [^[:alnum:]] - любой НЕ алфавитно-цифровой символ, то есть это полная противоположность [[:alnum:]]. То есть, любой класс вы можете инвертировать посредством '^'.
Подстановка претензий
\b - на границе слова
\B - не на границе слова
\A - в начале строки
\Z - в конце строки
\z - в конце текста
"здесь 10 слов\nтри начала строки и два конца строки \n"
"здесь 10 слов два начала строки и один конец строки \n"
Вспомним, что: 'слов\nдва' - это два слова.
/\bпре(\w+)ый\b/
В шаблоне мы сказали: в начале слова '\bпре', в середине буквы '(\w+)', в конце слова 'ый\b', будет искать все слова начинающиеся на 'пре' и оканчивающиеся на 'ый'.
/.*T\Z/
В этом шаблоне мы сказали: в начале что угодно, кроме перевода каретки '.*', то есть поиск идет только в строке, дальше 'T\Z' - будет искать 'T' в конце строки, то есть перед [\n]. Выведет только одну строку, у которой 'T' стоит перед [\n].
Модификаторы.
/шаблон/модификаторы
i - игнорировать регистр
/шаблон/i
будет искать шаблон, игнорируя регистр в тексте поиска.
s - метасимвол '.' соответствует и символу [\n], то есть классу [\0-\xFF]
/шаблон/s
будет искать шаблон, где '.' Игнорирует видит [\n], то есть метасимвол точка будет так же возвращать и перевод каретки на новую строку.
U - минимизировать числитель, то есть искать как можно меньше совпадений
/шаблон/U
будет искать шаблон, с как можно меньшим совпадением раз. Если мы ставили в шаблоне /a?/ - действие этого модификатора примерно такое же, как и минимизатора '?' в самом шаблоне.
m - претензии '^' и '$' учитывают [\n]
/шаблон/m
если в шаблоне будут метасимволы '^' и '$', то претензия '^' будет искать совпадение в начале строки, а претензия '$' будет искать совпадение в конце строки.
/^вино$/m
совапдение - "вино\n" (в строке 'вино')
нет совапдения - "ви\nно" (здесь 'вино' в разных строках)
D - претензия '$' не учитывает [\n]
/шаблон/D
если в шаблоне есть метасимвол '$'.
Претензия '$' будет искать совпадение в фактическом конце текста, игнорируя переводы каретки на новую строку [\n].
A - привязать шаблон к началу текста
/шаблон/D
Будет искать шаблон только в фактическом начале теста.
x - разрешить комментарии: пробел и #
/шаблон/x
здесь в шаблоне разрешены пробел и #, как комментарии, поэтому пробел и # надо предварять слешем, если только они не обозначают комментарии.
/слово
#комментарий
ищу/x
будет искать 'словоищу'. То есть, здесь игнорируются пробелы и все, что следует за знаком диез.
X - воспринимать неверную подстановку как ошибку.
/шаблон/X
S - предварительная оптимизация шаблона
/шаблон/S
e - используется в функции 'preg_replace' для ее активации
/шаблон/e
Сложные виды претензий.
(?=текст) - текст после точки совпадения должен соответствовать указанному
(?!текст) - текст после точки совпадения НЕ должен соответствовать указанному
(?<=текст) - текст до точки совпадения должен соответствовать указанному
(?<!текст) - текст до точки совпадения НЕ должен соответствовать указанному
(?<=)здесь находится точка совпадения(?=)
/(?<=%)\w+(?=%)/
Возвращает любое слово без пробелов (в шаблоне '\w+'), стоящее между парой "%" '(?<=%)(?=%)', но сами "%" не возвращаются, это отличие таких претензий, от обычных описанных выше.
Функции регулярных выражений.
ereg ('то что ищем', 'где ищем', 'массив совпадений');
Возвращает TRUE при совпадении и FALSE, если совпадений нет. Последний элемент можно не указывать.
<?php
$stroka = "http://www.php.net/index.html";
if ( ereg ( 'http',$stroka)){
echo"Совпало с http";
}
else {echo"Нет совпадений";}
// напечатает: Совпало с http
?>
eregi ('то что ищем', 'где ищем', 'массив совпадений');
То же самое, что и ereg , только без учета регистра. Последний элемент можно не указывать.
<?php
$stroka = "HTTP://www.php.net/index.html";
if ( eregi ( 'http',$stroka)){
echo"Совпало с http";
}
else {echo"Нет совпадений";}
// напечатает: Совпало с http
?>
preg_match ('/шаблон/модификаторы', 'где ищем', 'массив совпадений');
Аналог ereg , только с использованием шаблона. Последний элемент можно не указывать.
<?php
$stroka = "HTTP://www.php.net/index.html";
if ( preg_match ( '/http/',$stroka)){
echo"Совпало с http";
}
else {echo"Нет совпадений";}
// напечатает: Нет совпадений
?>
<?php
$stroka = "HTTP://www.php.net/index.html";
// добавим модификатор i - "без учета регистра" - аналог eregi
if ( preg_match ( '/http/i',$stroka)){
echo"Совпало с http";
}
else {echo"Нет совпадений";}
// напечатает: Совпало с http
?>
/^(http:\/\/)?([^\/]+)/i
В этом шаблоне написано: в начале должно быть 'http://' ноль или один раз '^(http:\/\/)?', потом должно быть все кроме '/' один или более раз '([^\/]+)'. Кроме этого, это два подшаблона и второй подшаблон совпадет с местом, где нет '/'.
<?php
$stroka = "HTTP://www.php.net/index.html";
if ( preg_match ( '/^(http:\/\/)?([^\/]+)/i', $stroka, $array)){
// $array[2] = совпадение во втором подшаблоне
// там не должно быть '/' и слева надо чтобы было http://,
// $array[0]=HTTP://www.php.net
// $array[1]=HTTP://
// $array[2]=www.php.net
$host = $array[2];
}
?>
Внимание: то есть, массив $array[0] - это совпадение со всем шаблоном, $array[1] - это совпадение с первым подшаблоном, $array[2] - это совпадение со вторым подшаблоном. Таким образом, ставя в шаблоне подшаболны, Вы сможете выводить в программу не только совпадения со всем шаблоном, но и совпадения с подшаблонами.
/[^\.]+\.[^\.]+$/
В этом шаблоне написано: в центре точка '\.', слева от нее должно быть все кроме точек один и более раз '[^\.]+', а в правой от точки части, тоже должно быть все кроме точек один и более раз и кроме этого, эта часть должна стоять в конце '[^\.]+$'.
<?php
$stroka = "www.php.net";
if ( preg_match ("/[^\.]+\.[^\.]+$/i", $stroka, $array)){
// $array[0] = совпадение со всем шаблоном
// тогда $array[0] = php.net
$domain = $array[0];
}
?>
ereg_replace ('что меняем', 'на что меняем', 'где меняем')
Заменит, если найдет, первый элемент на второй в третьем элементе.
<?php
$string = "В строке четыре слова";
$string = ereg_replace ('четыре', '4', $string);
echo $string;
// напечатает: В строке 4 слова
?>
eregi_replace ('что меняем', 'на что меняем', 'где меняем')
То же самое, что и 'ereg_replace', только без учета регистра
split ('разделитель', 'место которое делим', 'сколько раз делим')
Разбивает строку на части и возвращает в массиве. Последний элемент можно не указывать.
<?php
$stroka = "24/04/2005 18.46.23";
$array = split ('[/.: -]', $stroka);
// теперь $array[0] - 24, $array[1] - 04, $array[2] - 2005,
// $array[3] -18 , $array[4] - 46, $array[5] -23
?>
spliti ('разделитель', 'место которое делим', 'сколько раз делим')
Тоже что и split , только без учета регистра. Последний элемент можно не указывать.