В Вашем браузере отключены Cookies. Для правильной работы сайта Cookies необходимо включить!
1 € = 1.25 $

1 € = 10.05 грн.

1 € = 38.21 руб.

Язык: 
   
Авторизация    Запомнить
   Регистрация

Сообщения с форума

Ошибки в работе скрипта

Я проверил.После изменения типа, компания не появится в списке до тех пор, пока не будет заполнена информация о компании. После ... (madmis)
Борьба с мошенниками - ваши предложения!

Возможно они пробили в интернете информацию по фамилии и узнали имя и отчество. Ведь в наше время это не проблема. (AKabanchuk)
SD-FileShare - PHP-скрипт скачивания файлов, с учетом коли

Добавил логирование загрузок и сортировку в списке файлов. Пользуйтесь на здоровье. (madmis)
Проблемы с название сайта

Попробуйте поискать по тексту (в файлах). Футер хранится в template/bottom.html (madmis)

 » Статьи » Web-разработка » Регулярные выражения - синтаксис шаблонов. Часть 2. (официальная документация)

Регулярные выражения - синтаксис шаблонов. Часть 2. (официальная документация)

Утверждения

Утверждения - это проверки касательно символов, идущих до или после текущей позиции сопоставления, ничего при этом не поглощая (никакие символы исходного текста не ставятся в соответствие утверждениям). Наиболее простые варианты утверждений, такие как \b, \B, \A, \Z, \z, ^ и $ были рассмотрены ранее. Более сложные утверждения записываются как подмаски. Утверждения бывают двух видов: те, которые анализируют текст, предшествующий текущей позиции, и идущий после нее.

Сопоставление подмаски, содержащий утверждение, происходит обычным образом, за исключением того, что текущая позиция не изменяется. Утверждения касательно последующего текста начинаются с (?= для положительных утверждений и с (?! для отрицающих утверждений. Например, \w+(?=;) совпадает со словом, за которым следует символ ';', но при этом сама точка с запятой в совпадение не включается. А foo(?!bar) соответствует любому появлению "foo", после которого не идёт "bar". Заметим, что похожий шаблон (?!foo)bar не будет искать вхождение "bar", которому предшествует любая строка за исключением "foo". Но, тем не менее, он будет соответствовать любым вхождениям подстроки "bar", поскольку условие (?!foo) всегда TRUE, если следующие три символа - "bar". Для получения желаемого результата необходимо воспользоваться второй категорией утверждений.

Утверждения касательно предшествующего текста начинаются с (?<= для положительных утверждений и (?<! для отрицающих. Например, (?<!foo)bar не найдёт вхождения "bar", которым не предшествует "foo". Сами утверждения 'назад' ограничены так, чтобы все подстроки, которым они соответствуют, имели фиксированную длину. Но, в случае, если используются несколько альтернатив, они не обязаны иметь одинаковую длину. Таким образом шаблон (?<=bullock|donkey) корректен, но (?<!dogs?|cats?) вызовет ошибку во время компиляции. Ветки, которые соответствуют строкам разной длины, разрешены только на верхнем уровне утверждений касательно предшествующего текста. Это расширение относительно Perl 5.005, который требует чтобы все ветки соответствовали строкам одинаковой длины. Такое утверждение как (?<=ab(c|de)) не корректно, поскольку верхний уровень маски может соответствовать строкам разной длины, но его можно преобразовать к корректному шаблону, используя альтернативы на верхнем уровне: (?<=abc|abde). Утверждения касательно предшествующего текста реализованы так, что для каждой альтернативы текущая позиция временно переносится назад, на фиксированную ширину, после чего выполняется поиск соответствия условию. В случае, если перед текущей позицией недостаточно символов, поиск соответствия терпит неудачу. Утверждения назад в сочетании с однократными подмасками могут быть особенно удобны для поиска в конце строки; соответствующий пример приведен в конце раздела "Однократные подмаски".

Несколько утверждений (разных типов) могут присутствовать в утверждении, например: (?<=\d{3})(?<!999)foo совпадает с подстрокой "foo", которой предшествуют три цифры, отличные от "999". Следует понимать, что каждое из утвержений проверяется относительно одной и той же позиции в обрабатываемом тексте. Вначале выполняется проверка того, что предшествующие три символа - это цифры, затем проверяется, чтобы эти же цифры не являлись числом 999. Приведенный выше шаблон не соответствует подстроке "foo", которой предшествуют шесть символов, первые три из которых - цифры, а последние три не образуют "999". Например, он не соответствует строке "123abcfoo", в то время как шаблон (?<=\d{3}...)(?<!999)foo - соответствует. В этом случае анализируются предшествующие шесть символов на предмет того, чтобы первые три из них были цифрами, а последние три не образовали "999".

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

Утверждающие подмаски являются незахватывающими и неповторяемыми, поскольку бессмысленно повторять одно и то же несколько раз. Если в утверждении произвольного типа находится захватывающая подмаска, она нумеруется в той же последовательности, что и все остальные захватывающие подмаски, но захват соответствующих значений происходит только для положительных утверждений, поскольку для отрицающих это не имеет смысла.

В утверждениях обрабатывается не более, чем 200 захватывающих подмасок.

Однократные подмаски

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

В качестве примера, рассмотрим шаблон \d+foo в применении к строке 123456bar

После того, как \d+ будет сопоставлен с первыми шестью цифрами, сопоставление "foo" потерпит неудачу. После этого, в соответствие \d+, будет сопоставлено 5 цифр, после очередной неудачи будет сопоставлено 4 цифры и так далее. В конце концов весь шаблон потерпит неудачу. Однократные подмаски указывают, что если одна часть шаблона была сопоставлена, ее не стоит анализировать повторно. Применимо к приведенному выше примеру весь шаблон потерпел бы неудачу после первого же неудачного сопоставления с "foo". Записываются однократные шаблоны при помощи круглых скобок следующим образом: (?>. Например: (?>\d+)bar

Этот вид подмаски предотвращает повторный ее анализ в случае, если сопоставление последующих элементов терпят неудачу. Однако, это не мешает повторно анализировать любые другие элементы, в том числе предшествующие однократной подмаске.

Говоря другими словами, подмаски такого типа соответствуют той части подстроки, которой соответствовала бы одиночная изолированная маска, заякоренная на текущей позиции обрабатываемого текста.

Однократные подмаски являются незахватывающими. Простые примеры, подобные приведенному выше, можно охарактеризовать как безусловный захват максимального количества повторений. В то время как \d+ и \d+? корректируются так, чтобы остальные части шаблона так же совпали, (?>\d+) соответствует исключительно максимальной по длине последовательности цифр, даже если это приводит к неудаче при сопоставлении других частей шаблона.

Однократные подмаски могут включать в себя более сложные конструкции, а также могут быть вложенными.

Однократные подмаски могут использоваться совместно с утверждениями касательно предшествующего текста для описания эффективных сопоставлений в конце обрабатываемого текста. Рассмотрим простой шаблон abcd$ в применении к длинному тексту, который не соответствует указанной маске. Поскольку поиск происходит слева направо, вначале PCRE будет искать букву "a", и только потом анализировать следующие записи в шаблоне. В случае, если шаблон указан в виде ^.*abcd$. В таком случае вначале .* сопоставляется со всей строкой, после чего сопоставление терпит неудачу (так как нет последующего символа 'a'). После чего .* сопоставляется со всей строкой, кроме последнего символа, потом кроме двух последних символов, и так далее. В конечном итоге поиск символа 'a' происходит по всей строке. Однако, если шаблон записать в виде: ^(?>.*)(?<=abcd) повторный анализ для .* не выполняется, и, как следствие, может соответствовать только всей строке целиком. После чего утверждение проверяет последние четыре символа на совпадение с 'abcd', и в случае неудачи все сопоставление терпит неудачу. Для больших объемов обрабатываемого текста этот подход имеет значительный выигрыш во времени выполнения.

Если шаблон содержит неограниченное повторение внутри подмаски, которая в свою очередь также может повторяться неограниченное количество раз, использование однократных подмасок позволяет избегать многократных неудачных сопоставлений, которые длятся достаточно продолжительное время. Шаблон (\D+|<\d+>)*[!?] соответствует неограниченному количеству подстрок, которые состоят не из цифр, либо из цифр заключенных в <>, за которыми следует ? либо !. В случае, если в обрабатываемом тексте содержатся соответствия, время работы регулярного выражения будет невелико. Но если его применить к строке aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa это займет длительное время. Это связанно с тем, что строка может быть разделена между двумя частями шаблона многими способами, и все они будут опробованы (в примере мы использовали [?!], поскольку в случае одиночного символа в конце шаблона и PCRE и Perl выполняют оптимизацию. Они запоминают последний одиночный символ и в случае его отсутствия выдают неудачу). Если изменить шаблон на ((?>\D+)|<\d+>)*[!?], нецифровые последовательности не могут быть разорваны, и невозможность сопоставления обнаруживается гораздо быстрее.

Условные подмаски

В PCRE реализована возможность подчинять шаблон условию либо выбирать из двух условных подмасок в зависимости от успеха сопоставления предыдущей подмаски. Условные подмаски имеют две допустимые формы использования:

(?(condition)yes-pattern)
(?(condition)yes-pattern|no-pattern)

В случае успешного сопоставления условия condition, используется подмаска yes-pattern, в противном случае no-pattern (если он присутствует). Если указано более двух альтернатив, возникнет ошибка во время компиляции.

Условия бывают двух видов. В случае, если между скобками заключены цифры, условие будет выполняться в том случае, если подмаска с соответствующим номером была успешно сопоставлена. Рассмотрим следующий шаблон (он содержит незначащий пробел для удобства чтения, подразумевается использование модификатора PCRE_EXTENDED), разделив его для удобства на три смысловые части: ( \( )? [^()]+ (?(1) \) )

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

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

(?(?=[^a-z]*[a-z])
\d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} )

Приведен пример с утверждающим условием касательно предшествующего текста, которое выполняется для необязательной последовательности не-букв с последующей буквой. Говоря другими словами, указанное условие проверяет наличие хотя бы одной предшествующей буквы. В случае, если буква найдена, выполняется сопоставление с первой альтернативой, в противном случае - со второй альтернативой. Приведенный шаблон соответствует строкам двух видов: dd-aaa-dd либо dd-dd-dd, где aaaa - это буквы, а dd - цифры.

Комментарии

Служебная последовательность (?# обозначает начало комментария, который продолжается до ближайшей закрывающей скобки. Вложенные скобки не допускаются. Символы, находящиеся внутри комментария, не принимают участия в сопоставлении шаблона.

В случае, если используется модификатор PCRE_EXTENDED, неэкранированный символ '#' вне символьного класса также означает начало блока комментария, который длится до конца текущей строки.

Рекурсивные шаблоны

Рассмотрим задачу поиска соответствия со строкой, находящихся внутри неограниченного количества круглых скобок. Без использования рекурсии лучшее, что можно сделать - написать шаблон, который будет решать задачу для некоторой ограниченной глубины вложенности, так как обработать неограниченную глубину не предоставляется возможным. В Perl 5.6 предоставлены некоторые экспериментальные возможности, которые в том числе позвояляют реализовать рекурсию в шаблонах. Специально обозначение (?R) используется для указания рекурсивной подмаски. Таким образом, приведем PCRE шаблон, решающий поставленную задачу (подразумевается, что используется модификатор PCRE_EXTENDED, незначащие пробелы игнорируются): \( ( (?>[^()]+) | (?R) )* \)

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

Приведенный пример шаблона использует вложенные неограниченные повторения, поэтому использование однократных шаблонов значительно ускоряет процесс сопоставления, особенно в случаях, когда строка не соответствует заданной маске. Например, если его применить к строке: (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(), то несоответствие будет обнаружено достаточно быстро. Но в случае, если однократные шаблоны не используются, сопоставление будет затягиваться на длительное время, так как существует множество способов разделения строки между квантификаторами + и *, и все они должны быть проверены, прежде чем будет выдано сообщение о неудаче.

Значение, устанавливаемое для захватывающей подмаски будет соответствовать значению, захваченному на наиболее глубоком уровне рекурсии. В случае, если приведенный выше шаблон сопоставляется со строкой (ab(cd)ef), захваченным значением будет 'ef', которое является последним значением, принимаемым на верхнем уровне. В случае, если добавить дополнительные скобки \( ( ( (?>[^()]+) | (?R) )* ) \), захваченным значением будет "ab(cd)ef". В случае, если в шаблоне встречается более, чем 15 захватывающих скобок, PCRE требуется больше памяти для обработки рекурсии, чем обычно. Память выделяется при помощи функции pcre_malloc, и освобождается соответственно функцией pcre_free. Если память не может быть выделена, сохраняются данные только для первых 15 захватывающих скобок, так как нет способа выдать ошибку out-of-memory изнутри рекурсии.

Производительность

Некотрые элементы, которые могут встречаться в шаблонах, являются более эффективными, чем ряд других. Например, гораздо эффективней использовать символьный класс [aeiou] вместо набора альтернатив (a|e|i|o|u). Как правило, более простая конструкция является более эффективной. Книга Jeffrey Friedl'а содержит много обсуждений вопроса оптимизации регулярных выражений.

В случае, если шаблон начинается с .* и используется флаг PCRE_DOTALL, шаблон неявно заякоривается, так как он может совпадать только в начале строки. Но если PCRE_DOTALL не используется, PCRE не может выполнить соответствующую оптимизацию, так как в таком случае метасимвол '.' не соответствует символу начала строки (если обрабатываемые данные содержат переводы строк, такой шаблон может соответствовать шаблону не от начала строки, а от позиции непосредственно после перевода строки). Например, применяя шаблон (.*) second к строке "first\nand second" (где \n обозначает символ перевода строки), значение, захваченное первой подмаской, будет 'and'. Чтобы обработать все возможные точки соответствия, PCRE пытается сопоставить шаблон после каждого символа перевода строки.

В случае, если вы используете подобные шаблоны для обработки данных, не содержащих переводы строк, для лучшей производительности используйте модификатор PCRE_DOTALL, либо начинайте шаблон с ^.* для указания явного заякоривания. Это предотвратит PСRE от поиска символов новых строк и дополнительных попыток сопоставить шаблон с каждой такой найденной позицией.

Избегайте шаблонов, которые содержат вложенные неограниченные повторения. Сопоставление их со строками, не содержащими совпадений, занимает длительное время. Рассмотрим пример шаблона (a+)*

Он может соответствовать с "aaaa" 33-мя различными способами, и эта цифра очень быстро растет при увеличении строки. (В данном примере, квантификатор * может совпадать 0, 1, 2, 3 или 4 раза, и для каждого такого случая, кроме нуля, квантификатор + также может совпадать различное число раз.) Если остаток шаблона таков, что все совпадение терпит неуачу, PCRE должно попробовать все возможные варианты совпадения, что может потребовать огромного количества времени.

При помощи оптимизации можно отловить наиболее простые случаи, такие как (a+)*b где следом идёт литеральный символ. Прежде, чем производить стандартную процедуру поиска, PCRE проверяет в последующей подстроке наличие символа 'b', и, в случае отсутствия такового, попытка сопоставления немедленно завершается неудачей. Однако, когда последующего литерала нет, оптимизация не может быть применена. Вы можете ощутить разницу, сравнив поведение (a+)*\d с поведением приведенного выше шаблона. Первый определяет невозможность сопоставления практически сразу же, при сопоставлении со строкой состоящей из символов 'a', в то время как второй тратит длительное время на поиск в строках длинее 20 символов.

 

 

Оригинал статьи: http://www.pcre.ru/docs/php/text/stdsyntax/

Дата: 17.11.2010 | Автор: Administrator
Рейтинг: 0
 
0 голосов
1 2 3 4 5
 

Рекомендуемые продукты

Works on the engine Expert © SD-Group 2012 - 2017 RSS Developed using PHP Developed using MySql