PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (2): [1] 2 » 

> Описание: Узнаем что-то о регулярных выражениях
Champion Супермодератор
Отправлено: 24 Мая, 2009 - 14:19:57
Post Id



Активный участник


Покинул форум
Сообщений всего: 4350
Дата рег-ции: Авг. 2008  
Откуда: Москва


Помог: 57 раз(а)




О регулярных выражениях.

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

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

Это раздел о том, из чего состоят шаблоны.
Люброй шаблон должен быть ограничен символами-ограничителями. В качестве таких символов можно использовать любой не буквенно-цифровой символ кроме '\'.
Не рекомендуется использовать в качестве ограничителей и другие специальные символы, в виду того их использование внутри шаблона станет неудобным. Предпочтительнее всего использовать символ /, потому что он не выполняет никаких специальных фунций.
Символ, используемый как ограничитель шаблона внутри шаблона должен экранироваться.
Пример: '/pattern/i' - соответствует строке, в которой есть слово pattern. i - это модификатор. Забегая вперед, скажу, что он означает регистронезависимое сравнение.

1 - Спецсимволы. Сначала о них, потому что мне будет легч описать остальное.
\ - символ экранирования.
Пример: '/qwe\/rty/' - соответствует строке, в которой есть qwe/try. Символ / мы заэкранировали, после чего он перестал выполнять в данном месте свое специальное значение (он являлся ограничителем шаблона).
^ - символ начала данных.
$ - символ конца данных.
Пример: '/^pattern$/' - Соответствует строке, точно совпедеющей со словом pattern. Т.е. с буквы p строка начинается и после n заканчивается.
. - любой символ, кроме перевода строки. Но естьмодификатор, при использовании которого перевод строки тоже относится к "любым" символам.
Пример: '/pat.ern/' - Соответствует и строке, содержащей pattern, или patdern, или pat3ern...
[] - внутри этих скобок перечисляются символы, любой один символ из которых может стоять на данном месте. Это называется символьным классом. Спецсимволы, написанные в [] ведут себя немного по-другому. Это я напишу.
Пример: '/pat[aoe]rn/' - под соответствие попадут только строки, содержащие patarn, patorn или patern.
| - Или. Пример ниже.
() - подмаска.
? - одно или ноль вхождений предшествующего символа или подмаски.
* - любое количество вхождений предшествующего символа или подмаски. В том числе и ноль.
+ - одно или более вхождений.
Пример: '/as+(es|du)?.*r/' - Буква а, потом одна или больше букв s, после этого сочетание es или du может быть один раз, а может м ни разу, потом любое количество любых символов и буква r.
Здесь же скажу про еще одно значения символа ?. Метасимвол звездочка по умолчанию жадный (и другие тоже). Это значит, что в нашем примере вот этой части '.*r' будет соответствовать, например, подстрока asdrfsrsfdr. Как видно, до последней буквы r в нее попало еще две. Вот эту жадность можно выключить. Т.е. шаблон станет соответствовать только подстроке asdr. До первого r. Для этого надо в до того места где необходимо отключить жадность поставит модификатор (?U). Вот еще одно применение символам ? и ().
{a,b} - количество вхождений предшествующего символа или подмаски от а до б. Если б не указан, считается, что верхней границы нет. Например, * - то же самое, что {0,}. ? - то же, что {0,1}. {5,7} - 5,6 или 7 повторений.

a) Спецсимволы внутри символьного класса.
^ - отрицание.
Пример: [^da] - соответствует любому символу кроме d и a.
Пример: [^^] - соответствует любому символу кроме ^.
Пример: [d^a] - соответствует любому cимволу из перечисленных трёх. [\^da] - то же самое.
В последнем примере, как видно символ стоит не в нчале перчисления и свою метафункцию теряет. И экранировать его, кстати, тоже тут не надо.
- - внутри символьного класса означает символьный интервал.
Пример: [0-9a-e] - соответствует любому символу от 0 до 9 и от a до e. Если в символьном классе надо перечислить сам символ дефиса, то следует либо заэранироватьего, либо разместить перед ].
Осторожно в символьном классе надо использовать символ \. Если его поставить перед ], она окажется заэкранирована. Также окажется заэкранированным любой символ, который может быть заэкранирован. Иначе символ \ является обычным сиволом.
Символ $ тоже является обчным символом внутри символьного класса. И скобки тоже.

б) Символ \. Одна из его функций - снятие специального значения со спецсимволов. А другая, наоборот придание специальных функций обычным символам.
\cx - ctrl + x. На месте x может быть любой символ.
\e - escape.
\f - разрыв страницы.
\n, \r, \t - это нам и так привычно. Перевод строки, возврат каретки и табуляция.
\d - любой символ, означающий десятичную цифру.
\D - любой символ, не означающий десятичную цифру.
\s - любой пробельный символ.
\S - не пробельный.
\w - любоя цифра, буква или знак подчеркивания.
\W - любой символ, но не \w.
\b - граница слова. Можно использовать вместо (?<!\w)(?=\w) или аналогичных вариаций.
\B - не граница слова.
Две последние конструкции не соосветствуют никаким реальным символам.
\xHH - символ с шестнадцатиричным кодом HH. x - это именно буква икс.
\DDD - символ с восьмеричным кодом DDD. Или ссылка на подмаску.
По поводу ссылки на подмаску: '/([0-9]{2,3}).\1/' - 2 или 3 символа от 0 до 9, потом любая последовательность символов и те же 2 или 3 конкретных символа, которые соответствовали подмаске. То есть строка 'as34sdf34' - подойдет. Там 34, и там. А 'sd34dg32' - нет.
Если анализатор находит \x, он считывает максимальное количество последующих символов, которые могут быть шестнадцатиричным числом. Максимальное - это не больше двух. Если из три, то считается два, если меньше - то сколько есть.
Если анализатор находит \0, он поступает аналогично. Только считывает не 16ричные, а восмеричные цифры. До двух штук. То есть \0\x\0325 означает два символа с кодом ноль, символ с восьмеричным кодом 32 и пятерка.
Если после слеша стоит отличная от нуля цифра, то ту посложнее. Вот напишем такую вещь: \40. Если в шаблоне есть 40 подмасок, то это будет воспринято как ссылка на 40ю подмаску. Сороковую - в десятичной системе счисления. Если же подмасок меньше, то это будет воспринято как символ с восьмеричном кодом 40.
\040 - всегда символ с кодоми восьмериным 40.
\7 - всегда ссылка на подмаску.
\13 - в зависимости от ситуации.
В символьном классе возможно указывать символьные диапозоны с помощью из кодов: [\044-\056]
Стоит также отметить, что ссылок на подмаски не может быть больше, чем 99.

2 - Обычные символы. Это символы, не являющиеся специальными.

3 - Модификаторы. Указываются они либо в скобках, например так: (?Ui), либо после закрывающего символа '/pattern/Ui'.
i - регистронезависимость.
U - инвертирует жадность.
m - многострочный поиск.
s - если используется, то символ . соостветствует и переводу строки. Иначе она ему не соответствует.
x - заставляет игнорировать все неэкранированные пробельные символы, если они не перечислены в символьном классе. Удобно, когда энтерами и пробелами вы хотите навести удобночитаемость в регулярке.
При использовании модификаторов, можно использовать знак '-' для отключения модификатора. (?m-i) - Bключаем многострочный поиск и отключаем регистронезависимый.
Здесь надо сказать, что все модификаторы что-то включают. Или отключают, если указаны с минусом. А вот U инвертирует. Т.е. если была жадность включена, он выключит без всяких минусов.

4 - Утверждения. Утверждения - это проверки касательно символов, идущих до или после текущей позиции сопоставления. Например, \b - это утверждение, что предыдущий символ словесный, а следующий - нет, либо наоборот. Но это как бы встроенное утверждение, а мы тут сейчас свои собственные научимся писать.
Утверждения касательно последующего текста начинаются с (?= для положительных утверждений и с (?! для отрицающих утверждений.
Утверждения касательно предшествующего текста начинаются с (?<= для положительных утверждений и (?<! для отрицающих.

Например, под шаблон '/(?<!foo)bar/' подойдут вхождения "bar", которым не предшествует "foo". Т.е. qwefoobar этот шаблон проигнорирует, а asacdbar под него подойдет.
(?<=\d{3})(?<!999)foo совпадает с подстрокой "foo", которой предшествуют три цифры, отличные от "999". Следует понимать, что каждое из утвержений проверяется относительно одной и той же позиции в обрабатываемом тексте.
Утверждения могут быть вложенными, причем в произвольных сочетаниях: (?<=(?<!foo)bar)baz соответствует подстроке "baz", которой предшествует "bar", перед которой, в свою очередь, нет 'foo'.

a) Условные подмаски. По-моему, этого достаточно: (?(condition)yes-pattern|no-pattern)
Пример: (?(?=\d)u|p). (?=\d) - это условие. Мы утверждаем, что после этого места идет цифра. Если оно истино, то на данном месте должна стоять буква u. Иначе - p.

5 - Комментарии. Комментарии начинаются с (?# и продолжаются до ближайшей закрывающей скобки. Так же как /* */ в PHP - без учета вложенности.

Вот и всё. Этой теории, в принципе, должно хватить.

Функции PHP для работы с регелярными выражениями.
mixed preg_match ( string $pattern, string $subject [, array $&matches [, int $flags [, int $offset]]] )
Ищет в заданном тексте subject совпадения с шаблоном pattern . Если совпадение не найдено - вернет false.
В случае, если дополнительный параметр matches указан, он будет заполнен результатами поиска. Элемент $matches[0] будет содержать часть строки, соответствующую вхождению всего шаблона, $matches[1] - часть строки, соответствующую первой подмаске, и так далее.
$pattern - шаблон, $subject - где искать. В мануале есть пара примеров.

Похожая функция preg_match_all с теми же параметрами. Она отыскивает все совпадения в то время как preg_match - только первое.

array preg_split ( string $pattern, string $subject [, int $limit [, int $flags]] )
Возвращает массив, состоящий из подстрок заданной строки subject, которая разбита по границам, соответствующим шаблону pattern.
В случае, если параметр limit указан, функция возвращает не более, чем limit подстрок. Специальное значение limit, равное -1, подразумевает отсутствие ограничения

mixed preg_replace ( mixed $pattern, mixed $replacement, mixed $subject [, int $limit])
Выполняет поиск в строке subject совпадений с шаблоном pattern и заменяет их на replacement. В случае, если параметр limit указан, будет произведена замена limit вхождений шаблона; в случае, если limit опущен либо равняется -1, будут заменены все вхождения шаблона.
$replacement может содержать ссылки на подмаски шаблона. Таким образом, можно поменять в строке местами части, соостветствующие двум разным подмаскам.

mixed preg_replace_callback ( mixed $pattern, callback $callback, mixed $subject [, int $limit] ) Выполняет поиск по регулярному выражению и замену с использованием функции обратного вызова. Пример:
PHP:
скопировать код в буфер обмена
  1. <?PHP
  2. function rnd_replace($matches)
  3. {
  4.         if ($matches[1] > 'c')
  5.                 return '('.$matches[1].'->'.rand(0, 9).')';
  6.         else
  7.                 return $matches[1];
  8. }
  9. $src = 'sd4vaf345g534fgh43kj3';
  10. $res = preg_replace_callback('/(\D)/', 'rnd_replace', $src);
  11. echo $res
  12. ?>

Все нецифры, которые больше, чем с будут заменены сами увидите на что.


Задачи к разделу
1. У вас есть php-код. Строковые индексы массивов в нем не заключены в кавычки. Вам надо заключить их в кавычки. Но учтите, что индексами массивов в коде могут быть и переменные, и функции - они не должны оказаться в кавычках. Объявленные константы в расчет не берем.
2. Дана строка. Проверьте, все ли символы в ней уникальны.
3. Проверьте синтаксическую правильность строки, содержащей e-mail
4. Проверьте синтаксическую правильность даты. Формат даты 'dd-mm-yyyy'. День и месяц, меньший 10 может быть записан одной цифрой. Неплохо было бы проверить так же на то сколько в месяце дней. Високосность года учитывать не надо.
5. Найдите все ссылки на странице.
 
 Top
EuGen Администратор
Отправлено: 25 Мая, 2009 - 12:04:23
Post Id


Профессионал


Покинул форум
Сообщений всего: 9097
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Champion пишет:
/ - этим символом ограничивается шаблон.

Не соглашусь. Шаблон ограничивается любыми двумя одинаковыми символами.
Скажем,

и

Есть одно и то же
(Пишу в урок, раз уж решили разрешить обсуждения в самих уроках)


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
Champion Супермодератор
Отправлено: 25 Мая, 2009 - 12:34:58
Post Id



Активный участник


Покинул форум
Сообщений всего: 4350
Дата рег-ции: Авг. 2008  
Откуда: Москва


Помог: 57 раз(а)




Да, действительно. Спасибо, поправил.
 
 Top
Roler
Отправлено: 25 Мая, 2009 - 13:02:16
Post Id



Посетитель


Покинул форум
Сообщений всего: 458
Дата рег-ции: Авг. 2008  
Откуда: Россия


Помог: 1 раз(а)




Кажется, самый полный тутор, который я видел. Спасибо.
 
 Top
EuGen Администратор
Отправлено: 25 Мая, 2009 - 13:22:18
Post Id


Профессионал


Покинул форум
Сообщений всего: 9097
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Позволю себе задачку отписать)
Из реальной жизни. Ситуация была такая - прежний программист имел дурную привычку писать обращение к элементам массивов без указания кавычек, то есть как то так:

Это, естественно, вызывало Notice.
Собственно, задача такая: при помощи preg_replace заменить подобные выражения на правильные, то есть, как в примере:


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
Roler
Отправлено: 25 Мая, 2009 - 16:39:52
Post Id



Посетитель


Покинул форум
Сообщений всего: 458
Дата рег-ции: Авг. 2008  
Откуда: Россия


Помог: 1 раз(а)




Пробую слёту, ни за что не ручаюсь Улыбка

CODE (text):
скопировать код в буфер обмена
  1. $text = preg_replace("/\$(.*)\[(.*)\]/u","$\1['\2']",$text);

(Отредактировано автором: 25 Мая, 2009 - 16:44:09)

 
 Top
EuGen Администратор
Отправлено: 25 Мая, 2009 - 16:49:30
Post Id


Профессионал


Покинул форум
Сообщений всего: 9097
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Да, да, варианты

Тоже нужно рассматривать.


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
Roler
Отправлено: 25 Мая, 2009 - 16:57:45
Post Id



Посетитель


Покинул форум
Сообщений всего: 458
Дата рег-ции: Авг. 2008  
Откуда: Россия


Помог: 1 раз(а)




А вот это хз, лично я бы просто прогнал раза три, чуть-чуть модифицировав, обычно не бывает вложенности больше третьего уровня)

(Отредактировано автором: 25 Мая, 2009 - 16:58:59)

 
 Top
EuGen Администратор
Отправлено: 25 Мая, 2009 - 17:01:58
Post Id


Профессионал


Покинул форум
Сообщений всего: 9097
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Интерес задачи как раз в том, чтобы сделать замену для
CODE (text):
скопировать код в буфер обмена
  1.  
  2. $rgData[key0][key1]...[keyN]
  3.  


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
Roler
Отправлено: 25 Мая, 2009 - 17:07:04
Post Id



Посетитель


Покинул форум
Сообщений всего: 458
Дата рег-ции: Авг. 2008  
Откуда: Россия


Помог: 1 раз(а)




Такая, своего рода, бесконечность мне самому нужна Радость

P.S. Что-то у меня и обычная регулярка не пашет. Не пойму, в чём ошибка.

(Отредактировано автором: 25 Мая, 2009 - 17:53:02)

 
 Top
Champion Супермодератор
Отправлено: 25 Мая, 2009 - 19:10:58
Post Id



Активный участник


Покинул форум
Сообщений всего: 4350
Дата рег-ции: Авг. 2008  
Откуда: Москва


Помог: 57 раз(а)




Roler, ты по чуть чуть. Сделай сначала preg_match, посмотри, находит ли регулярка соответствия. Сделай, чтоб находила, если не находит.

Сейчас все вместе напишем синтаксичесkий анализатор PHP))
 
 Top
EuGen Администратор
Отправлено: 25 Мая, 2009 - 19:53:55
Post Id


Профессионал


Покинул форум
Сообщений всего: 9097
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Нет, ну варианты
CODE (text):
скопировать код в буфер обмена
  1.  
  2. $rgData[$rgInternal[key0]..[keyN]][some_function({..args..})]
  3.  

и т.д. ,в принципе тоже нужно отработать (дабы не заключить в кавычки и не сделать строковой константой `верхнее` выражение)


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
Champion Супермодератор
Отправлено: 25 Мая, 2009 - 20:06:10
Post Id



Активный участник


Покинул форум
Сообщений всего: 4350
Дата рег-ции: Авг. 2008  
Откуда: Москва


Помог: 57 раз(а)




Да вроде просто всё

$code = '$var[ind1][ind2][ind3]';
$res = preg_replace('/\[(\w+)\]/', '[\'\1\']', $code);
echo $res;
 
 Top
EuGen Администратор
Отправлено: 25 Мая, 2009 - 20:15:37
Post Id


Профессионал


Покинул форум
Сообщений всего: 9097
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Конечно, никаких сложностей. Важно только понять, что именно стоит заменять.


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
Roler
Отправлено: 25 Мая, 2009 - 21:36:17
Post Id



Посетитель


Покинул форум
Сообщений всего: 458
Дата рег-ции: Авг. 2008  
Откуда: Россия


Помог: 1 раз(а)




Выражение вроде придумал, но первоначальный вариант всё не могу заставить работать)
 
 Top
Страниц (2): [1] 2 »
Сейчас эту тему просматривают: 1 (гостей: 1, зарегистрированных: 0)
« Уроки php »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB