Логические операции в регулярных выражениях

Категория: / DEV Блог / PHP (LAMP)
В регулярных выражениях perl есть синтаксические выражение, позволяющие в шаблонах использовать простые логические конструкции:
  • (?= шаблон) - после этой точки есть фрагмент текста, который соответствует указанному регулярному выражению
  • (?! шаблон) - после этой точки нет текста, который бы соответствовал указанному регулярному выражению,
  • (?<= шаблон) - перед этой точкой есть фрагмент текста, соответствующий указанному регулярному выражению,
  • (?<! шаблон) - перед этой точкой нет фрагмента текста, соответствующего указанному регулярному выражению.
  • (?#текст) - комментарий. Текст комментария игнорируется.
  • (?:шаблон) или (?модификаторы:шаблон) - группирует элементы шаблона. В отличие от обычных круглых скобок, не создает нумерованной переменной. Например, модификатор i не будет делать различия между строчными и заглавными буквами, однако область действия этого модификатора будет ограничена только указанным шаблоном.
  • (?=шаблон) - "заглядывание вперед". Требует, чтобы после текущей точки находился текст, соответствующий данному шаблону. Такая, конструкция обрабатывается как условие или мнимый символ, поскольку не включается В результат поиска. Например, поиск с помощью команды /w+(?=\s+)/ найдет слово, за которым следуют один или несколько "пробельных символов", однако сами они в результат не войдут.
  • (?!шаблон) - случай, противоположный предыдущему. После текущей точки не должно быть текста, соотносимого с заданным шаблоном. Так, если шаблон w+(?=\s) - это слово, за которым следует "пробельный символ", то шаблон w+(?!\s) - это слово, за которым мет "пробельного символа".
  • (?<=шаблон) - заглядывание назад. Требует, чтобы перед текущей точкой находился соответствующий текст. Так, шаблон (?<=\s)w+ интерпретируется как слово, перед которым имеется пробельный символ (в отличие от заглядывания вперед, заглядывание назад может работать только с фиксированным числом проверяемых символов).
  • (?<!шаблон) - отрицание предыдущего условия. Перед текущей точкой не должно быть текста, соотносимого с заданным шаблоном. Соответственно, от команды /(?<!\s)w+/ требуется найти слово, перед которым нет пробельного символа.
  • (?{код}) - условие (мнимый символ), которое всегда выполняется. Сводится к выполнению команд perl в фигурных скобках. Вы можете использовать эту конструкцию, только если в начале сценария указана команда use re 'eval'. При последовательном соотнесении текста и шаблона, когда perl доходит до такой конструкции, выполняется указанный код. Если полного соответствия для оставшихся элементов найти не удалось, то при возврате левее данной точки шаблона вычисления, проделанные с локальными переменными, откатываются назад. (Условие является экспериментальным. В документации, прилагаемой в perl, можно найти довольно детальное рассмотрение (с примерами) работы этого условия и возможных трудностей в случае его применения.)
  • (?>шаблон) - "независимый" или "автономный" шаблон. Используется для оптимизации процесса поиска, поскольку запрещает "поиск с возвратом". Такая конструкция соответствует подстроке, на которую налагается заданный шаблон, если его закрепить в текущей точке без учета последующих элементов шаблона. Например, шаблон (?>а*)аb в отличие от a*ab не может соответствовать никакой строке. Если поставить в любом месте шаблон а*, он съест все буквы а, не оставив ни одной шаблону ab. (Для шаблона а*аb "аппетит" квантификатор * будет ограничен за счет работы поиска с возвратами: после того как на первом этапе не удастся найти соответствие между шаблоном и текстом, perl сделает шаг назад и уменьшит количество букв а, захватываемых конструкцией а*.)
  • (?(условие)шаблон-да|шаблон-нет) или (?(условие)шаблон-да) - условный оператор, который подставляет тот или иной шаблон в зависимости от выполнения заданного условия. Более подробно описан в документации perl.
  • (?модификаторы) - задает модификаторы, которые локальным образом меняют работу процедуры поиска. В отличие от глобальных модификаторов, имеют силу только для текущего блока, то есть для ближайшей группы круглых скобок, охватывающих конструкцию, Например, шаблон ((?i)text) соответcтвует слову "text" без учета регистра.


Пример "заглядывания"-lookahead

// ищем текст big, за которым не следует слово dog
if(preg_match("/big+(?!dog)/i", $string))

// ищем dog, за которым идет символ :
if(preg_match("/dog+(?=:)/", $string, $match))

// ищем dog, перед которым будет big
if(preg_match("/(?<=big)dog/i", $string)) или
if(preg_match("/(?<!big)dog/i", $string))


Анализируем лог апача на предмет рефереров

Необходимо выбрать все уникальные рефы из лога и положить в отдельный файл.
При этом учесть, что рефы с самого сайта и пустые ("-") нужно отбрасывать.

$f = file_get_contents('access.log');
preg_match_all("#HTTP\/\d\.\d\" 200 \d+ \"(?!(?:-|http:\/\/(?:www\.)?skillz))(.*)\"#Um", $f, $reps);
file_put_contents('referers.log', implode("\n", array_unique($reps[1])));