Многим материал этой статьи покажется ненужным, так как большинство задач с использованием регулярных выражений решаются средствами, которые я описал в первой и второй статье. Но несмотря на это, я считаю, что без этой статьи цикл статей будет незаконченным.
Сначала немного отвлечемся. Как вы опишите
Пример:
Мой директор спрашивает, как найти
В синтаксисе регулярных выражений есть возможность описать, что стоит до, а что стоит после того участка строки, который нам нужно найти. Считайте, что есть возможность, не называя точного адреса, описать местоположение банка. Если сумеете описать, между чем и чем находится банк, а также сумеете описать, что это именно банк, а не кафе, то считайте, что вам не нужно давать точный адрес.
Каждый раз при помощи регулярных выражений происходит поиск совпадений. Поиск проводится по строке, в строке ищется подстрока. Теперь научимся задавать условие, что должно совпасть перед подстрокой и после нее. Условие совпадения, которое идет перед подстрокой, называют ретроспективной проверкой, условие совпадения, которое идет после подстроки, называется опережающей проверкой. Можно объяснить также, что ретроспективная проверка совпадает слева, опережающая – справа.
Позитивные и негативные проверки
Хорошо, если можно описать, что следует перед искомой подстрокой, а что после. А что если нужно описать, что НЕ идет перед либо после искомой подстроки? Для этого опережающую и ретроспективную проверку делят еще каждую на две:
Опрежающая позитивная, опережающая негативная проверки.
Ретроспективная позитивная, ретроспективная негативная проверка.
Опережающая позитивная проверка указывает, что условие описывает, что должно обязательно присутствовать после искомой подстроки. Опережающая негативная проверка описывает, что ни в коем случае не должно стоять после искомой строки. Аналогично с ретроспективной проверкой только условие ищется перед искомой подстроки.
Ретроспективная проверка
Позитивная ретроспективная проверка либо проверка слева описывается специальной последовательностью символов:
(?<=) скобки группируют условие, вопросительный знак, показывает, что содержимое скобок надо рассматривать не как группировку символов, чтобы их запомнить, а группировку символов для выполнения над выражением внутри скобок других действий. Вспомним, что просто скобки описывают группу символов и запоминают в переменные все, что в них находится, а скобки с вопросом и двоеточием указывают на специальное действие: группировка без запоминания. Символ(ы) после вопрсительного знака воспринимаются как указание, какое именно действие надо выполнить. Итого: знак
Ретроспективная негативная проверка описывается подобной последовательностью символов:
(?<!) Посмотрите, что знак равно сменился на восклицательный знак и проверка сразу поменяла «полярность» т.е. из позитивной превратилась в негативную. Логика простая если вспомнить, что для проверки условия «неравно», отрицания равно, во многих языках программирования используется последовательность символов: !=
Опережающая проверка
Если вы поняли описание ретроспективной проверки, то понять суть опережающей проверки вам будет несложно.
Для описания позитивной опережающей проверки используется последовательность символов:
(?=) все как и раньше, скобки указывают что символы группируются для
Для описания негативной опережающей проверки используется последовательность символов:
(?!) тоже самое, только знак равно заменили отрицанием – восклицательным знаком.
Пример №1
Часто возникает проблема по парсингу интересующих программиста данных из HTML, который не всегда хорошего качества, все было бы терпимо, если бы еще не вставки на javascript'е, вот пример такого текста:
те цифры, которые написаны через точку, являются ценами. Задача состоит в том, чтобы собрать все цены, которые находятся между тегами <a>... </a>
Видим, что помимо цен между заданными тегами, есть такие, которые идут сразу после тега <TD>, а также стоят между тегами <B>...</B>. Ясно, что описать достаточно точно содержимое атрибутов тега <A> представляется задачей не самой легкой, поэтому надо ее упростить! Любой тег имеет закрывающий знак '>', наша задача описать, что этот знак идет перед ценой, но так как перед ценой может стоять тег <B> и тег <TD>, но эти цены нам не нужны. Каким образом мы узнаем, что цена стоит между тегами <A>...</A>? По тегу, который идет после цены, если это не тег </B>, то это будет либо тег </A> либо <BR>, а так же по тегу перед ценой если этот тег <TD>.
Путем таких размышлений мы пришли к выводу, что должно стоять справа, а что должно стоять слева искомой строки, которая описывается как цифры, разделенные точкой:
d*.d*
То, что должно совпасть слева, мы описали как символ '>', записываем:
(?<=>) – выглядит немного странно, но совпадение справа записывается вот так (?<=), а внтури него после ?<= идет символ '>'
То, что должно совпасть спарава описывается
(?=)
внутри мы пишем </A>
Теперь опишем, что не должно стоять перед ценой:
(?<!<TD>) перед ценой не должен стоять тег <TD>, это и есть негативная ретроспективная проверка.
При помощи негативной опережающей проверки опишем, что не должно стоять справа цены:
(?!</B>) справа от цены не должен стоять тег </B>
результирующее регулярное выражение, которое описывает все приведенные условия выглядит вот так:
Пример №2
style="background-image:url(/editor/em/);"
Для проведения вышеописанной операции надо:
1. попросить хозяина хоста использовать контент, размещенный на его сайте.
2. найти в тексте все строки, подобные приведенной выше, и выделить в них относительный путь к файлу
3. сформировать файл в котором будут выводиться изображения при помощи <img src=полный_путь_к_изображению>
Делаем:
В переменную $content получаем исходный код страницы. А дальше используя регулярные выражения ищем относительные пути, которые прописаны в стилях. Каждый раз, когда я описываю, как я реализовал пример, я сначала тщательно описываю, что ищем, и тщательно описываю, в каком контексте происходит поиск. Проанализировав исходный код страницы стало понятно, что кроме как в описании стилей относительные пути к изображениям нигде не используются. Слева от относительного пути идет последовательность символов: url(
Справа от относительного пути стоит закрывающаяся круглая скобка.
Между этими последовательностями символов могут быть буквы латинского алфавита, цифры и слеши, а также точка перед расширением файла.
Начнем с простого. Символы латинсокого алфавита, цифры, точка и слеш описываются символьным классом:
[
их может быть сколько угодно, на самом деле больше 3 (имя файла, минимум один символ, точка, расширение, минимум один символ), но в данном случае, зная контекст, это некритично, поэтому указываем квантификатор *
[
Слева должны идти 'url(' и мы это описываем при помощи позитивной ретроспективной проверки:
(?<=url()
Но обратите внимание на то, что скобка в регулярных выражениях является спецсимволом группировки, поэтому чтобы она стала символом, надо перед ней поставить другой спецсимвол – слеш.
(?<=url()
Справа от относительного пути должна стоять закрывающаяся круглая скобка. Это условие описывается при помощи позитивной опережающей проверки:
(?=))
Как видите, перед одной из скобок стоит слеш, что означает, что она интепретируется не как спецсимвол, а как литерал.
Ниже приведен полный код на PHP, который выполняет все действия, кроме вопроса о разрешении использовать контент:
На берегах Пахры
Михайловское Варварино Васюнино Красное Страдань Шаганино Кузенево Поливаново Лемешово «Дубровицы» Ивановское ПлещеевоПодольские объявления Подольск - авто Подольск - недвижимость Подольск - Работа Подольск - Услуги Подольск - Путешествия Подольск - Предложения Подольск - ЗОО Подольск - Продаю Подольск - Куплю