Авто   Интересная история   Искусство   Карьера   Мастер   Недвижимость   Оружие   Подольск   Реклама   «Деловой Подольск»  
Содержание   А Б В Г Д Е Ж З И К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Э Ю Я

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

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

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


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


Введение

Регулярные выражения – язык шаблонов (на самом деле это математический термин, кому интересно, читайте про детерминированные и недетерминированные конечные автоматы)
Для того, чтобы выполнить какое-то действие, надо указать какое именно, обычно действие указывается функцией:
В РНР это будет, например, вот так:
preg_replace – заменить
preg_match – найти соответствие
preg_split – разбить
тоже самое с функциями стандарта Posix типа ereg, только они отличаются тем, что в отличие от Preg у них другой механизм обработки поиска совпадений.


Обработка шаблона происходит посимвольно, как вы будете искать букву d в слове stadium? правильно, первое, что приходит на ум, это перебрать все буквы слова stadium и сравнить их с буквой, которую ищем, итак получаем простой перебор. Считайте, что вы уже научились использовать РВ, только осталось выучить как задавать шаблон того, что вы хотите найти в строке.


Шаблон – это своеобразный указатель, что искать в строке.
Искать можно цифры, буквы, невидимые символы (пробел, таб)


Как вы в слове stadium будете искать букву d либо букву m пока не произойдет первое совпадение одного из символов? правильно, тоже перебором, возьмете каждую букву слова и будете сравнивать с тем, что вам надо найти поочередно с d и c m. Но вам каждый раз теперь придется сравнивать букву слова (строки) с двумя буквами условия поиска. Таким образом, вы создали свой первый символьный класс, который на языке регулярных выражений записывается вот так:
[dm] – это означает, что вы ищете либо d либо m 
Что нужно, чтобы указать, что вы ищете в строке то, что может быть любой буквой алфавита? надо либо перечислить их все
[abc....xyz]
либо просто написав интервал
[a-z]
Внимание смертельный номер, такое возможно с русскими буквами
[а-я]
а так же с цифрами
[0–9]
но есть еще заглавные
[A-Z]
т.е. чтобы получить символьный класс со всеми буквами латинского алфавита надо поставить в шаблоне
[a-zA-Z]


Но вот такой символьный класс описывает только один символ, а у вас в строке их вон сколько, это решается при помощи квантификаторов.


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

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


Как в условии задать поиск двух символов?
Приведу простой пример без символьных классов, который уже был затронут выше:
Ищем последовательность iu в слове stadium. Как вы это сделаете? Ну естественно перебором:
1. берем первый символ слова и сравниваем его с первым символом условия 's' неравно 'u'
2. берем второй символ слова и сравниваем его с первым символа условия 't' неравно 'i'
3. делаем так до тех пор, пока j-й символ в слове не совпадет с первым символом условия поиска. В этот момент 'i' равно 'i' (мы находимся в выделенной позиции в слове stadium, и выделенной позиции условия поиска iu ), как только выполнилось это условие, надо взять следующий символ из слова и из условия (предварительно запомнив, где произошло первое совпадение, очень важный шаг!)
4. сравниваем следующий символ слова со вторым символом условия 'u' равно 'u' Поздравляю, исходная комбинация найдена!
5. Что делать если условие 4 не выполнилось, если вместо слова stadium нам подсунули слово с ошибкой stadiem?
Вернитесь к шагу 3 и вспомните, какой важный шаг вы сделали. Вы запомнили, где нашли первое совпадение. Совпадения следующего символа слова со следующим символом условия не произошло, поэтому надо взять следующий символ слова, в нашем слове с ошибкой это будет stadiem и сравнить снова с первым символом условия! и продолжать выполнять пункт 3. до конца слова, понятно, что совпадение найдено не будет.


Искать по двум определенным символам мы уже научились, теперь будем учиться пользоваться символьными классами.
Допустим, у нас есть строки:
abcd12345efg
fghi56789qwe


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


Выше я рассказывал, как описать символ, который будет совпадать с любой латинской буквой, напомню, для этого мы используем символьный класс:
[a-z] (пока не обращаем внимания на то, что есть еще заглавные буквы)
символ условия, который совпадет с любой цифрой, описывается вот таким символьным классом:
[0–9]
Вернемся к первоначальному заданию. Нам надо найти строки с четырьмя буквами вначале, сразу после которых идут пять цифр.
Из того, что мы уже знаем, можно написать:
[a-z][a-z][a-z][a-z][0–9][0–9][0–9][0–9][0–9]
Посмотрите сами, такая форма записи условия поиска будет работать! так как мы описали каждым символьным классом один символ в условии поиска. Вам не кажется, что слишком громоздкое условие поиска получается? И тут на помощь приходят квантификаторы. Вспоминаем английский:
quantity – количество. Т.е. квантификатор – то, что выражает количество чего-то, в нашем случае количество символов в условии поиска. Упрощаем условие поиска при помощи квантификаторов:
[a-z]{4}[0–9]{5}
Все! кто не догадался, в фигурных скобках написано, сколько символов, описанных в символьном классе, может идти подряд в строке в которой ищем совпадение.
Вот и получается, что после пяти любых букв латинского алфавита идет 5 любых цифр. Поиск происходит точно также как я описывал выше, только символы в условии поиска задаются не явно, а при помощи символьных классов.
Каждый символьный класс описывает только один символ, количество схожих символов идущих подряд описывается квантификаторами.


Естественно подобное задание количества символов в условии поиска не является единственным. Квантификаторы бывают разные!
[a-z]{1,3} означает, что подряд может идти от одного до трех букв латинского алфавита.
[a-z]{2,} означает, что может идти минимум 2 буквы латинского алфавита подряд.
Но квантификатор в фигурных скобках не является единственным способом задать количество символов идущих подряд, которые описаны символьным классом.
[a-z]* означает, что подряд может идти сколь угодно букв латинского алфавита, а может быть, что и ни одной, идентично [a-z]{0,} .
[a-z]+ означает, что обязательно подряд должна идти минимум одна буква латинского алфавита, но максимальное количество не указано, идентично [a-z]{1,}
[a-z]? означает, что количество латинских букв не должно превышать 1, буква также может вообще отсутствовать, идентично [a-z]{0,1}.


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

Вернемся в самое начало статьи, где мы искали перебором букву d в слове stadium. Условие поиска совпадения, которое описывается одним неспециальным символом, называется литералом.
Есть строки:
abcdefg
abcddefg
abcdddefg
abcddddefg
Требование:
Написать условие поиска совпадения для всех строк.
Решение:
abcd{1,4}efg
Только что вы видели, как я применил квантификатор к литералу. К литералам можно применять любой из вышеприведенных квантификаторов.
Ясно, что применив условие поиска avcd{1,4}efg для строки abcefg, совпадение найдено не будет, так как квантификатор {1,4} подразумевает, что после abc перед efg идет миним одна, максимум четыре буквы d.


Символьные классы «для продвинутых»

Вы уже увидели, как символьные классы облегчают описание условия совпадения. Разберемся с ними окончательно.
Что может входить в символьный класс? В символьный класс может входить любой литерал, а так же интервалы литералов. Для описания интервалов литералов используется символ '-', который ставится между первым символом интервала и последним. Приведу примеры задания различных интервалов в одном символьном классе:
[1–5] — числа в диапазоне от 1 до 5
[a-f] — буквы латинского алфавита от a до f
[a-fq-x] — буквы латинского алфавита от a до f и от q до x
как вы заметили, в последнем символьном классе я использую два диапазона.


Представим, что вам нужно описать условие, что в определенном месте строки могут стоять символы: либо a, либо g, либо 7, либо 4. Что делать? Писать символьный класс:
[ag47]
Объяснение простое, в символьном классе можно перечислять допустимые в условии поиска литералы. Перечисление литералов можно совмещать с указанием интервалов:
[14a-kz] — это означает, что символ в строке может совпадать с 1, 4, буквами латинского алфавита c a по k, а так же с буквой z. Естественно литералами могут быть не только буквы и цифры, а так же знаки препинания, математические знаки, например ',' (запятая), '!' (восклицательный знак), '+' (плюс), '-' (минус). Стоп, скажете вы, какой минус, если он же используется для описания интервалов. Правильно, если вы поставите минус между a и z, то это будет интервал, но если вы поставите минус сразу же после открытой квадратной скобки, то это будет минус! И вот пример:
[-,a-z] — означает, что в символьный класс входят минус, запятая, а так же буквы латинского алфавита от a до z.


А как написать символьный класс, в который входят все символы кроме заданных? Например, все кроме a, b, c? Для этого существует специальный спецсимвол отрицания: ^ (крышка) Пишем:
[^abc] – все символы (не буквы, а именно символы) кроме букв латинского алфавита a, b, c.


Запомнить все!

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


Специально для таких целей существуют группирующие и одновременно сохраняющие круглые скобки.
Пример:
Строка может состоять из 5-ти букв латинского алфавита, после которых следует знак минуса, после которого следуют четыре цифры от 1 до 8.
Задание:
1. проверить строки на соответствие условию
2. вернуть в программу четыре цифры, что на данном этапе будет означать только то, что эти четыре цифры надо как-то выделить в условии поиска
Если мы просто хотим проверить строку на соответствие условию совпадения, то условие поиска будет вот таким:
[a-z]{5}[1–8]{4}
но нам надо запомнить цифры, поэтому добавляем инструкцию запоминания:
[a-z]{5}([1–8]{4})
Как видите, то, что надо запомнить, выделено круглыми скобками. Внутри функции, которая будет выполнять операцию со строкой при помощи вышеприведенного условия, совпадение будет запоминаться в специальных переменных, в PHP к ней можно обращаться через 1 в Perl — $1. В одном условии поиска может быть несколько инструкций запоминания:
([a-z]{5})([1–8]{4}) — проверит строку на совпадение с условием, в случае удачного совпадения, запомнит пять букв в 1 ($1), четыре цифры в 2 ($2). Если обратиться к переменной , то окажется, что в ней хранится вся совпавшая строка, которая была описана условием.


Ближе к реалиям

Тот, у кого хватило желания дочитать до этого места, уже много понимает, пытается писать свои собственные условия поиска по строке, но у него не получается. Скорее всего это происходит из-за того, что вы не знаете многих мелочей работы с регулярными выражениями. Про некоторые я расскажу прямо сейчас.
Строка имеет начало и конец. Вы скажете, что это понятно каждому, но скорее всего вам придется немного изменить свое понятие о строках. Считайте, что вначале каждой строки и в конце каждой строки стоит невидимый символ. При поиске в реальной программе это надо учитывать, поставив в начале условия поиска символ '^' (начало строки), а в конце условия поиска '$' (конец строки). Поэтому пример с пятью буквами и четырьмя цифрами (как и все остальные после них вышеприведенные) надо переписать:
^[a-z]{5}[1–8]{4}$
теперь при помощи этого условия на самом деле можно проверить строки
asbvc1234
sdwtsv1234
на соответствие условию.
Не стоит путать '^' (крышку) в символьном классе и ее же при описании условия совпадения. Крышка, поставленная вначале условия, поиска соответствует началу строки, крышка, поставленная после квадратной скобки открывающей описание символьного класса, будет спецсимволом отрицания (все, кроме того, что присутствует в символьном классе), крышка, поставленная на любой другой позиции внутри символьного класса, кроме первой, будет просто литералом.


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


В программах для того, чтобы показать,где начинается условие поиска (регулярное выражение), используют разделители.
Пример:
preg_match(«/$[a-z0–9]/», $string,$mathces);
посмотрите что указано в кавычках первого аргумента функции, сначала идет слеш, потом символ начала строки, потом идет символьный класс, потом идет снова слеш. Вот именно первый и последний слеш символизируют, что внутри них заключено регулярное выражение. Это пришло из Perl, где сразу за разделитемя еще можно указывать модификаторы, про которые позже. На данном этапе нужно знать, что в записи условия поиска нужны ограничители (два идентичных символа, не обязательно слеш, многие используют тильду)

Разбор примеров

Все примеры взяты из вопросов, которые люди задают на различных форумах. Примеры буду разбирать на том языке, на котором сам пишу: PHP.


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


$user = $_POST['username'];
if(!preg_match(«/^[a-zA-Z0–9]+$/», $user))
{
echo «Имя пользователя задано в неправильном формате»;
}else
{
echo «Имя пользователя задано в правильном формате»;
}


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


Так как регистрационное имя пользователя должно состоять из латинских букв, а также цифр, то надо написать символьный класс, который будет удовлетворять этому условию:
[a-zA-Z0–9]
в этот символьный класс входит три интервала, первый интервал a-z (все символы от маленькой буквы a до маленькой буквы z), второй интервал A-Z (аналогично, но с большими буквами), третий интервал 0–9 (цифры от 0 до 9). Мы описали только одну букву, из которой может состоять регистрационное имя, но таких букв может быть... а теперь как раз надо ответить на вопрос, сколько таких букв может быть? Да сколько угодно, скажете вы, а я скажу, что вы неправы.


Регистрационное имя должно состоять минимум из одной буквы! и я считаю, чти это обязательное условие при прохождении регистрации, поэтому надо данный факт описать. Вспоминаем про квантификаторы:
[a-zA-Z0–9]+
Плюс '+', как раз тот квантификатор, который говорит, что в строковой переменной $user должен быть минимум один символ, который соответствует условию.


А теперь надо сказать регулярному выражению, что условию должна соответствовать вся строка, от начала до конца, поэтому добавляем в регулярное выражение символ начала строки '^' вначале регулярного выражения и символ конца строки '$' в конец:
^[a-zA-Z0–9]+$


Теперь надо объяснить функции preg_match, что строка ^[a-zA-Z0–9]+$ является регулярным выражением, надо поставить ограничители, я ставлю слеш '/':
preg_match(«/^[a-zA-Z0–9]+$/»,$user)


2.
Есть люди, которые сами себе усложняют жизнь, эти люди называются программистами и системными администраторами, причем часто они усложняют жизнь не только себе, а еще и друг другу, а тут еще и босс приходит и видит, что на сайте компании можно регистрироваться, а имя пользователя еще как-то хитро проверяется, в 80% случаев вышеприведенная задача усложняется боссом, надо либо расширить набор символов, что делается простым добавлением символов в символьный класс, либо ужесточаются условия. Например, ставится условие, что имя пользователя может состоять как из букв латинского алфавита, так и из цифр, но первый символ имени пользователя должен быть обязательно буквой латинского алфавита! Дописываем регулярное выражение:
^[a-zA-Z][a-zA-Z0–9]*$


Как уже давно известно, символьный класс описывает только один символ. Наша задача как раз в том и состоит, чтобы описать один символ (первый):
[a-zA-Z]
тут два интервала, описывают первый символ и дают понять, что никаких цифр в первом символе проверяемой строки быть не может.
Из размышлений в предыдущем примере явно следовало, что регистрационное имя пользователя должно быть длинной минимум в один символ. Мы уже описали первый символ строки, но он может быть и единственным, после него может быть сколько угодно символов, либо может их вообще не быть, но регулярное выражение совпадет только тогда, когда все последующие символы будут удовлетворять условию, что они являются либо буквами латинского алфавита, либо цифрами.
[a-zA-Z0–9]
Первый обязательный символ описан, остальные символы не обязательны, поэтому меняем квантификатор с '+' на '*', Ставим символы начала и конца строки:
^[a-zA-Z][a-zA-Z0–9]*$

Колесниченко Сергей

23/01/2006  
дополнительно
как можно оптимизировать PHP-Nuke
Отрисовка связанного дерева с помощью XSLT - как с умом использовать XSLT и XPath
Регулярные выражения.
Когда и почему не следует использовать регулярные выражения
Регулярные выражения. Часть 3
Шерлок Холмс спешит на помощь вебпрограммисту или регулярные выражения на пальцах
Регулярные выражения. Часть вторая
Сверхдинамичные веб-интерфейсы
юю
юю
back home top
Подольск Адреса История Подольские Форумы Объявления Справочник Фото Журнал
Подольское городское информационное агенство podolsk.biz размещение сайтов о городе Подольск и Подольском районе. имя вида название.podolsk.biz, почтовые адреса вида название@podolsk.biz
Подольское агенство podolsk.biz

Отдел рекламы 8903 1347521

поиск по Подольску



Подольск   карта сайта   Реклама на «podolsk.biz»  

Подольск рейтинг