perlre
СОДЕРЖАНИЕ
- ИМЯ
- ОПИСАНИЕ
- Основы
- Модификаторы
- Регулярные выражения
- Квалификация метасимволов
- Расширенные шаблоны
- Обратное отслеживание
- Запуск скриптов
- Специальные управляющие глаголы обратного отслеживания
- Предупреждение об использовании \1 вместо $1
- Повторные шаблоны, сопоставляющие подстроку нулевой длины
- Объединение частей регулярных выражений
- Создание собственных движков регулярных выражений
- Частота выполнения встраиваемого кода
- Поддержка PCRE/Python
ИМЯ
perlre - Регулярные выражения Perl
ОПИСАНИЕ
На этой странице описана синтаксис регулярных выражений в Perl.
Если вы раньше не использовали регулярные выражения, доступен учебный вводный курс в perlretut. Если вы знаете немного об этом, доступен краткий вводный курс в perlrequick.
За исключением раздела "Основы", на этой странице предполагается, что вы знакомы с основами регулярных выражений, такими как, что такое "шаблон", как он выглядит и как он в основном используется. Для справки о том, как они используются, а также различные примеры, см. обсуждения m//, s///, qr// и "??" в "Операторы экранирования регулярных выражений" в perlop.
В версии v5.22, use re 'strict' применяет более строгие правила, чем обычно, при компиляции шаблонов регулярных выражений. Он может находить вещи, которые, хотя и легальны, могут не соответствовать вашим намерениям.
Основы
Регулярные выражения — это строки со специфическим синтаксисом и значением, описанным в этом документе и дополнительных документах, на которые он ссылается. Эти строки называются "шаблонами". Шаблоны используются для определения того, имеет ли какая-либо другая строка, называемая "целевой", указанные в шаблоне характеристики. Мы называем это "сопоставлением" целевой строки шаблону. Обычно сопоставление выполняется путем использования целевой строки в качестве первого операнда, а шаблона — в качестве второго операнда одного из двух бинарных операторов =~ и !~, перечисленных в "Операторы связи" в perlop; и шаблон будет преобразован из обычной строки одним из операторов в "Операторы экранирования регулярных выражений" в perlop, как показано ниже:
$foo =~ m/abc/ Это оценивается как истина тогда и только тогда, когда строка в переменной $foo содержит последовательность символов "a", "b" и затем "c". (Оператор =~ m, или оператор сопоставления, описан в "m/PATTERN/msixpodualngc" в perlop.)
Шаблоны, которые ещё не сохранены в какой-либо переменной, должны быть ограничены символами разделителей с обеих сторон. Часто, как в примере выше, используются обратные слэши, и типичный способ записи шаблона в документации — с этими слэшами. В большинстве случаев разделитель — один и тот же символ, но есть несколько случаев, где символ выглядит так, как будто у него есть зеркальное отображение, где открытая версия — это начальный разделитель, а закрытая — конечный разделитель, например
$foo =~ m<abc> В большинстве случаев шаблон оценивается в контексте двойных кавычек, но можно выбрать разделители для принудительного использования одинарных кавычек, например
$foo =~ m'abc' Если шаблон содержит свой разделитель внутри него, этот разделитель необходимо экранировать. Представление его обратным слэшем (например, "/foo\/bar/") служит для этой цели.
Любой одиночный символ в шаблоне соответствует такому же символу в целевой строке, если этот символ не является метасимволом со специальным значением, описанным в этом документе. Последовательность неметасимволов соответствует той же последовательности в целевой строке, как мы видели выше с m/abc/.
Лишь несколько символов (все они являются символами пунктуации ASCII) являются метасимволами. Наиболее часто используемый — точка ".", которая обычно соответствует почти любому символу (включая саму точку).
Вы можете заставить символы, которые обычно функционируют как метасимволы, интерпретироваться буквально, предварив их обратным слэшем "\", так же, как разделитель шаблона должен быть экранирован, если он также встречается внутри шаблона. Таким образом, "\." соответствует только буквальной точке, "." вместо его обычного значения. Это означает, что обратный слэш также является метасимволом, поэтому "\\" соответствует одному "\". И последовательность, содержащая экранированный метасимвол, соответствует той же последовательности (но без экранирования) в целевой строке. Так, шаблон /blur\\fl/ соответствует любой целевой строке, содержащей последовательность "blur\fl".
Метасимвол "|" используется для сопоставления одного или другого. Таким образом
$foo =~ m/this|that/ ИСТИНА тогда и только тогда, когда $foo содержит либо последовательность "this", либо последовательность "that". Как и все метасимволы, предваряющий обратный слэш "|" делает его соответствующим простому символу пунктуации; в его случае — вертикальной черте.
$foo =~ m/this\|that/ ИСТИНА тогда и только тогда, когда $foo содержит последовательность "this|that".
Вы не ограничены только одним "|".
$foo =~ m/fee|fie|foe|fum/ ИСТИНА тогда и только тогда, когда $foo содержит любую из этих 4 последовательностей из детской истории "Джек и бобовый стебель".
Как видите, "|" связывает менее тесно, чем последовательность обычных символов. Мы можем переопределить это, используя метасимволы группировки, круглые скобки "(" и ")".
$foo =~ m/th(is|at) thing/ ИСТИНА тогда и только тогда, когда $foo содержит либо последовательность "this thing", либо последовательность "that thing". Части строки, соответствующие частям шаблона, заключённым в скобки, обычно доступны отдельно для использования впоследствии в шаблоне, подстановке или программе. Это называется "захватом", и оно может быть сложным. См. "Группы захвата".
Первый вариант включает все от последнего разделителя шаблона ("(", "(?:" (описано позже), и т.д. или начала шаблона) до первого "|", и последний вариант содержит всё от последнего "|" до следующего закрывающего разделителя шаблона. Вот почему принято заключать альтернативы в скобки: чтобы уменьшить путаницу относительно того, где они начинаются и заканчиваются.
Альтернативы проверяются слева направо, поэтому выбирается первая найденная альтернатива, для которой соответствует все выражение. Это означает, что альтернативы необязательно жадные. Например: при сопоставлении foo|foot с "barefoot", только часть "foo" будет соответствовать, так как эта альтернатива проверяется первой и успешно соответствует целевой строке. (Это может показаться неважным, но это важно, когда вы захватываете соответствующий текст, используя скобки.)
Помимо того, что отнимает специальное значение метасимвола, предшествующий обратный слэш меняет некоторые буквы и цифровые символы от сопоставления просто самих себя, а вместо этого имеет особое значение. Они называются "экранированными последовательностями", и все они описаны в perlrebackslash. Последовательность с обратным слэшем (буквы или цифры), которая в данный момент не имеет специального значения для Perl, вызовет предупреждение, если включены предупреждения, так как они зарезервированы для потенциального будущего использования.
Одна из таких последовательностей — \b, которая соответствует границе какого-то рода. \b{wb} и ещё несколько дают специализированные типы границ. (Они все подробно описаны начиная с "\b{}, \b, \B{}, \B" в perlrebackslash.) Обратите внимание, что они не соответствуют символам, а нулевым пространствам между символами. Это пример утверждения нулевой ширины. Рассмотрим ещё раз
$foo =~ m/fee|fie|foe|fum/ Это оценивается как ИСТИНА, если помимо этих 4 слов в $foo присутствуют любые из последовательностей "feed", "field", "Defoe", "fume" и многие другие. При умелом использовании \b (или, что лучше (поскольку оно разработано для работы с естественным языком), \b{wb}), мы можем гарантировать, что будут сопоставляться только слова гиганта:
$foo =~ m/\b(fee|fie|foe|fum)\b/
$foo =~ m/\b{wb}(fee|fie|foe|fum)\b{wb}/ Последний пример показывает, что символы "{" и "}" являются метасимволами.
Ещё одно применение последовательностей экранирования — указание символов, которые нельзя (или нежелательно) записывать буквально. Подробное описание этих последовательностей приведено в "Экранирование символов" в perlrebackslash, но в следующих трёх абзацах кратко описаны некоторые из них.
Различные управляющие символы могут быть записаны в стиле языка C: "\n" соответствует символу новой строки, "\t" — табуляции, "\r" — возврату каретки, "\f" — переводу страницы, и т. д.
Более обще, \nnn, где nnn — строка из трёх восьмеричных цифр, соответствует символу, кодовый пункт которого равен nnn. Вы можете легко столкнуться с проблемами, если не используете ровно три цифры. Поэтому всегда используйте три, или, начиная с Perl 5.14, вы можете использовать \o{...} для указания любого числа восьмеричных цифр.
Аналогично, \xnn, где nn — шестнадцатеричные цифры, соответствует символу, порядковый номер которого равен nn. Опять же, использование не ровно двух цифр чревато ошибками, но вы можете использовать \x{...} для указания любого числа шестнадцатеричных цифр.
Помимо того, что "." является метасимволом, он является примером "класса символов", который может соответствовать любому одиночному символу из заданного набора. В данном случае, набор включает практически все возможные символы. Perl предопределяет несколько классов символов помимо "."; о них есть отдельная справочная страница, perlrecharclass.
Вы можете определить собственные пользовательские классы символов, поместив в нужное место(а) шаблона список всех символов, которые вы хотите включить в набор. Это делается путём заключения списка в [] скобки. Эти классы называются "классами символов в скобках", когда мы точны, но часто слово "в скобках" опускают. (Обычно это не вызывает путаницы.) Это означает, что "[" символ — это ещё один метасимвол. Он сам по себе ничего не соответствует; он используется только для того, чтобы сообщить Perl, что то, что следует за ним, — это класс символов в скобках. Если вы хотите сопоставить буквальную левую квадратную скобку, вы должны экранировать её, как "\[". Соответствующая "]" — тоже метасимвол; опять же, он сам по себе ничего не соответствует, но только указывает Perl на конец вашего пользовательского класса. Это пример "иногда метасимвола". Он не является метасимволом, если нет соответствующего "[", и соответствует своей буквальной себе:
print "]" =~ /]/; # prints 1 Список символов внутри класса символов задаёт набор символов, сопоставляемых с классом. "[abc]" соответствует одному символу "a", "b" или "c". Но если первый символ после "[" это "^", класс вместо этого соответствует любому символу, не входящему в список. Внутри списка "-" символ указывает на диапазон символов, так что a-z представляет все символы между "a" и "z", включительно. Если вы хотите, чтобы либо "-" или "]" сами были членами класса, поместите их в начало списка (возможно, после "^"), или экранируйте их обратной косой чертой. "-" также интерпретируется буквально, когда он находится в конце списка, непосредственно перед закрывающей "]". (Все следующие указывают один и тот же класс из трёх символов: [-az], [az-], и [a\-z]. Все они отличаются от [a-z], которое определяет класс, содержащий двадцать шесть символов, даже на наборах символов на основе EBCDIC.)
В классах символов в скобках есть много нюансов; полные подробности находятся в "Классы символов в скобках" в perlrecharclass.
Метасимволы
"Основы" представили некоторые метасимволы. Этот раздел предоставляет все из них. Большинство из них имеют то же значение, что и в команде egrep.
Только "\" всегда является метасимволом. Другие являются метасимволами только иногда. В следующей таблице перечислены все они, обобщается их использование и приводятся контексты, где они являются метасимволами. Вне этих контекстов или если они предваряются "\", они соответствуют соответствующему знаку препинания. В некоторых случаях их значение варьируется в зависимости от различных модификаторов шаблона, которые изменяют поведение по умолчанию. См. "Модификаторы".
PURPOSE WHERE
\ Escape the next character Always, except when
escaped by another \
^ Match the beginning of the string Not in []
(or line, if /m is used)
^ Complement the [] class At the beginning of []
. Match any single character except newline Not in []
(under /s, includes newline)
$ Match the end of the string Not in [], but can
(or before newline at the end of the mean interpolate a
string; or before any newline if /m is scalar
used)
| Alternation Not in []
() Grouping Not in []
[ Start Bracketed Character class Not in []
] End Bracketed Character class Only in [], and
not first
* Matches the preceding element 0 or more Not in []
times
+ Matches the preceding element 1 or more Not in []
times
? Matches the preceding element 0 or 1 Not in []
times
{ Starts a sequence that gives number(s) Not in []
of times the preceding element can be
matched
{ when following certain escape sequences
starts a modifier to the meaning of the
sequence
} End sequence started by {
- Indicates a range Only in [] interior
# Beginning of comment, extends to line end Only with /x modifier Обратите внимание, что большинство метасимволов теряют своё специальное значение, когда встречаются в классе символов в скобках, за исключением "^", который имеет другое значение, когда находится в начале такого класса. И "-" и "]" являются метасимволами только в ограниченных позициях внутри классов символов в скобках, в то время как "}" является метасимволом только при закрытии специальной конструкции, начатой "{".
В контексте двойных кавычек, как обычно, нужно быть осторожным с "$" и неметасимволом "@". Они могут интерполировать переменные, что может или не может быть тем, что вы имели в виду.
Эти правила были разработаны для компактности выражения, а не для удобочитаемости и поддерживаемости. Модификаторы шаблона "/x и /xx" позволяют вставлять пробелы для улучшения удобочитаемости. И использование re 'strict' добавляет дополнительную проверку, чтобы поймать некоторые опечатки, которые могли бы безмолвно скомпилироваться во что-то нежелательное.
По умолчанию символ "^" гарантированно соответствует только началу строки, символ "$" только концу (или перед символом новой строки в конце), и Perl производит некоторые оптимизации с предположением, что строка содержит только одну строку. Встроенные новые строки не будут соответствовать "^" или "$". Однако вы можете захотеть обработать строку как буфер с множеством строк, так что "^" будет соответствовать после любой новой строки внутри строки (за исключением случая, когда новая строка — последний символ строки), и "$" будет соответствовать перед любой новой строкой. За счёт немного большего накладных расходов вы можете сделать это, используя модификатор "/m" оператора сопоставления с шаблоном. (Более старые программы делали это, устанавливая $*, но этот параметр был удалён в perl 5.10.)
Для упрощения многострочных подстановок символ "." никогда не соответствует новой строке, если вы не используете модификатор /s, который фактически говорит Perl, что строка должна рассматриваться как одиночная строка — даже если это не так.
Модификаторы
Обзор
Поведение сопоставления по умолчанию может быть изменено с помощью различных модификаторов. Модификаторы, относящиеся к интерпретации шаблона, перечислены непосредственно ниже. Модификаторы, которые изменяют способ использования шаблона Perl, подробно описаны в "Операторы цитирования регулярных выражений" в perlop и "Подробности синтаксического анализа цитируемых конструкций" в perlop. Модификаторы можно добавлять динамически; см. "Расширенные шаблоны" ниже.
-
m -
Обрабатывать строку, с которой сравнивается шаблон, как многострочную. То есть, изменить
"^"и"$"с соответствия началу первой строки строки и концу её последней строки на соответствие началу и концу каждой строки внутри строки. -
s -
Обрабатывать строку как одиночную строку. То есть, изменить
"."на соответствие любому символу, даже новой строке, которой он обычно не соответствует.Использование вместе, как
/ms, позволяет"."соответствовать любому символу, в то время как"^"и"$"соответствуют, соответственно, сразу после и сразу перед новой строкой внутри строки. -
i -
Выполнять сопоставление шаблонов без учёта регистра. Например, "A" будет соответствовать "a" при использовании
/i.Если правила сопоставления по локале активны, преобразование регистра берётся из текущей локали для кодовых точек меньше 255 и из правил Unicode для больших кодовых точек. Однако сопоставления, которые пересекали бы границу правил Unicode/не-Unicode (ords 255/256), не будут успешны, если только локаль не является UTF-8. См. perllocale.
Существует ряд символов Unicode, которые соответствуют последовательности нескольких символов при использовании
/i. Например,LATIN SMALL LIGATURE FIдолжен соответствовать последовательностиfi. В настоящее время Perl не может этого сделать, когда несколько символов находятся в шаблоне и разделены группами, или когда один или несколько из них квантифицированы. Таким образом"\N{LATIN SMALL LIGATURE FI}" =~ /fi/i; # Matches "\N{LATIN SMALL LIGATURE FI}" =~ /[fi][fi]/i; # Doesn't match! "\N{LATIN SMALL LIGATURE FI}" =~ /fi*/i; # Doesn't match! # The below doesn't match, and it isn't clear what $1 and $2 would # be even if it did!! "\N{LATIN SMALL LIGATURE FI}" =~ /(f)(i)/i; # Doesn't match!Perl не соответствует нескольким символам в классе символов в скобках, если символ, который отображается на них, не указан явно, и он вообще не соответствует им, если класс символов инвертирован, что в противном случае могло бы быть очень запутанным. См. "Классы символов в скобках" в perlrecharclass и "Отрицание" в perlrecharclass.
-
xиxx -
Улучшить удобочитаемость шаблона, разрешая пробелы и комментарии. Подробности в "/x и /xx"
-
p -
Сохранить сопоставленную строку, чтобы
${^PREMATCH},${^MATCH}, и${^POSTMATCH}были доступны для использования после сопоставления.В Perl 5.20 и выше это игнорируется. Благодаря новой механике копирования при записи,
${^PREMATCH},${^MATCH}, и${^POSTMATCH}будут доступны после сопоставления независимо от модификатора. -
a,d,l, иu -
Эти модификаторы, все новые в 5.14, влияют на используемые правила набора символов (Unicode и т. д.), как описано ниже в "Модификаторы наборов символов".
-
n -
Предотвратить захват метасимволов группирования
(). Этот модификатор, новый в 5.22, предотвратит заполнение$1,$2, и т.д..."hello" =~ /(hi|hello)/; # $1 is "hello" "hello" =~ /(hi|hello)/n; # $1 is undefЭто эквивалентно размещению
?:в начале каждой группы захвата:"hello" =~ /(?:hi|hello)/; # $1 is undef/nможет быть отменён на уровне группы. В качестве альтернативы можно использовать именованные захваты."hello" =~ /(?-n:(hi|hello))/n; # $1 is "hello" "hello" =~ /(?<greet>hi|hello)/n; # $1 is "hello", $+{greet} is # "hello" - Другие модификаторы
-
Есть ряд флагов, которые можно найти в конце конструкций регулярных выражений, которые не являются общими флагами регулярных выражений, но относятся к выполняемой операции, такой как сопоставление или замена (соответственно
m//илиs///).Флаги, описанные далее в "Использование регулярных выражений в Perl" в perlretut:
c - keep the current position during repeated matching g - globally match the pattern repeatedly in the stringМодификаторы, специфичные для замены, описанные в "s/PATTERN/REPLACEMENT/msixpodualngcer" в perlop:
e - evaluate the right-hand side as an expression ee - evaluate the right side as a string then eval the result o - pretend to optimize your code, but actually introduce bugs r - perform non-destructive substitution and return the new value
Модификаторы регулярных выражений обычно записываются в документации как например, "модификатор /x", даже если разделитель в данном случае может не быть косой чертой. Модификаторы /imnsxadlup также могут быть встроены в само регулярное выражение с использованием конструкции (?...), см. "Расширенные паттерны" ниже.
Подробности о некоторых модификаторах
Некоторые модификаторы требуют более подробного объяснения, чем то, что дано в "Обзоре" выше.
/x и /xx
Один /x говорит анализатору регулярных выражений игнорировать большинство пробелов, которые не экранированы обратным слешем и не находятся внутри скобочной группы символов, а также не находятся внутри символов многосимвольного метапаттерна, такого как (?i: ... ). Вы можете использовать это, чтобы разбить ваше регулярное выражение на более читаемые части. Также символ "#" обрабатывается как метасимвол, вводящий комментарий, который продолжается до закрывающего разделителя шаблона или до конца текущей строки, если шаблон продолжается на следующей строке. Таким образом, это очень похоже на обычный Perl-комментарий. (Вы можете включить закрывающий разделитель в комментарий только в том случае, если вы предваряете его обратным слешем, поэтому будьте осторожны!)
Использование /x означает, что если вы хотите реальные пробелы или "#" символы в шаблоне (вне скобочной группы символов, которая не затронута /x), то вам нужно либо экранировать их (используя обратные слэши или \Q...\E), либо закодировать их с помощью восьмеричного, шестнадцатеричного или \N{} или \p{name=...} эскейпов. Неэффективно пытаться продолжить комментарий на следующей строке, экранируя \n с помощью обратного слеша или \Q.
Вы можете использовать "(?#text)", чтобы создать комментарий, который заканчивается раньше, чем конец текущей строки, но text также не может содержать закрывающий разделитель, если он не экранирован обратным слешем.
Распространённая ошибка заключается в том, что вы забываете, что "#" символы (вне скобочной группы символов) начинают комментарий при /x и не поддаются буквальному соответствию. Просто помните об этом, пытаясь понять, почему конкретный /x шаблон не работает так, как ожидалось. Внутри скобочной группы символов "#" сохраняет свой неспециальный, буквальный смысл.
Начиная с Perl v5.26, если модификатор содержит второй "x" внутри него, эффект одного /x усиливается. Единственное отличие заключается в том, что внутри скобочных групп символов, неэкранированные (обратным слешем) пробелы и символы табуляции не добавляются в группу символов и, следовательно, могут быть вставлены для повышения читабельности групп символов:
/ [d-e g-i 3-7]/xx
/[ ! @ " # $ % ^ & * () = ? <> ' ]/xx может быть легче понять, чем эквивалентные сжатые варианты
/[d-eg-i3-7]/
/[!@"#$%^&*()=?<>']/ Обратите внимание, что это, к сожалению, не означает, что ваши скобочные группы символов могут содержать комментарии или занимать несколько строк. # внутри группы символов по-прежнему является просто буквальным #, и не вводит комментарий. И, если закрывающая скобка не находится в одной строке с открывающей, символ новой строки (и всё на следующих строках) до окончания ] будет частью группы символов, так же, как если бы вы написали \n.
В совокупности эти функции значительно повышают читабельность регулярных выражений Perl. Вот пример:
# Delete (most) C comments.
$program =~ s {
/\* # Match the opening delimiter.
.*? # Match a minimal number of characters.
\*/ # Match the closing delimiter.
} []gsx; Обратите внимание, что всё внутри \Q...\E остаётся не затронутым /x. И обратите внимание, что /x не влияет на интерпретацию пробелов внутри одного многосимвольного конструкта. Например, (?:...) не может иметь пробел между "(", "?", и ":". Внутри любых разделителей такого конструкта разрешённые пробелы не затрагиваются /x, а зависят от конструкта. Например, все конструкции с фигурными скобками в качестве разделителей, такие как \x{...} могут содержать пробелы внутри и рядом с фигурными скобками, но не где-либо ещё, и без других пробельных символов. Исключение составляют свойства Unicode, которые следуют правилам Unicode, о которых см. "Свойства, доступные через \p{} и \P{}" в perluniprops.
Набор символов, которые считаются пробелами, — это те, которые Unicode называет "Пробельные символы шаблона", а именно:
U+0009 CHARACTER TABULATION
U+000A LINE FEED
U+000B LINE TABULATION
U+000C FORM FEED
U+000D CARRIAGE RETURN
U+0020 SPACE
U+0085 NEXT LINE
U+200E LEFT-TO-RIGHT MARK
U+200F RIGHT-TO-LEFT MARK
U+2028 LINE SEPARATOR
U+2029 PARAGRAPH SEPARATOR Модификаторы набора символов
/d, /u, /a, и /l, доступные начиная с 5.14, называются модификаторами набора символов; они влияют на правила набора символов, используемые для регулярного выражения.
Модификаторы /d, /u, и /l вряд ли будут вам полезны, поэтому не стоит о них беспокоиться. Они существуют для внутреннего использования Perl, чтобы сложные структуры данных регулярных выражений могли быть автоматически сериализованы и позже точно восстановлены, включая все их нюансы. Но, поскольку Perl не может хранить секреты, и могут быть редкие случаи, когда они будут полезны, они здесь документированы.
Модификатор /a может быть полезным. Его цель — позволить коду, который в основном работает с данными ASCII, не беспокоиться о Unicode.
Короче говоря, /l устанавливает набор символов в соответствии с текущей Lокальностью в момент выполнения совпадения шаблона.
/u устанавливает набор символов в Unicode.
/a также устанавливает набор символов в Unicode, НО добавляет несколько ограничений для безопасного по отношению к ASCII сопоставления.
/d — это старое, проблемное, поведение набора символов по умолчанию до версии 5.14. Его единственное назначение — принудительно установить это старое поведение.
В любой момент времени активен ровно один из этих модификаторов. Их существование позволяет Perl сохранить первоначальное скомпилированное поведение регулярного выражения, независимо от правил, действующих при фактическом выполнении. И если оно интерполировано в более крупное регулярное выражение, оригинальные правила продолжают применяться к нему и не затрагивают другие части.
Модификаторы /l и /u автоматически выбираются для регулярных выражений, скомпилированных в рамках различных пragma, и мы рекомендуем в целом использовать эти пragma вместо явного указания этих модификаторов. Во-первых, модификаторы влияют только на сопоставление шаблонов и не распространяются даже на любые замены, тогда как использование пragma даёт согласованные результаты для всех соответствующих операций в пределах их областей действия. Например,
s/foo/\Ubar/il найдёт "foo" с использованием правил текущей локали для нечувствительного к регистру сопоставления, но /l не влияет на то, как работает \U. Скорее всего, вы хотите, чтобы оба использовали правила локали. Для этого необходимо скомпилировать регулярное выражение в рамках use locale. Это неявно добавляет /l, и применяет правила локали к \U. Урок заключается в том, чтобы use locale, а не /l явно.
Аналогично, лучше использовать use feature 'unicode_strings' вместо,
s/foo/\Lbar/iu чтобы получить правила Unicode, так как \L в первом (но не обязательно во втором) также будут использовать правила Unicode.
Более подробную информацию о каждом из модификаторов см. ниже. Скорее всего, вам не нужно знать эту информацию для /l, /u, и /d, и вы можете перейти к /a.
/l
означает использовать правила текущей локали (см. perllocale) при сопоставлении шаблонов. Например, \w найдёт символы-слова в этой локали, и "/i" нечувствительное к регистру сопоставление будет соответствовать правилам сгибания регистра локали. Используемая локаль будет той, которая действует в момент выполнения сопоставления шаблона. Она может отличаться от локали времени компиляции и может меняться от одного сопоставления к другому, если была вызвана функция setlocale().
До версии 5.20 Perl не поддерживал многобайтовые локали. Начиная с этой версии, поддерживаются локали UTF-8. Скорее всего, другие многобайтовые локали никогда не будут поддерживаться. Однако во всех локалях могут быть символы с кодами выше 255, и они всегда будут обрабатываться как Unicode независимо от действующей локали.
Согласно правилам Unicode, существуют некоторые нечувствительные к регистру сопоставления, которые пересекают границу 255/256. За исключением локалей UTF-8 в Perl 5.20 и более поздних версий, это запрещено в /l. Например, 0xFF (на платформах ASCII) не сопоставляется без учёта регистра с символом в 0x178, LATIN CAPITAL LETTER Y WITH DIAERESIS, потому что 0xFF может не быть LATIN SMALL LETTER Y WITH DIAERESIS в текущей локали, и у Perl нет способа узнать, существует ли этот символ в локали, и если да, то какой это код символа.
В локали UTF-8 в Perl 5.20 и более поздних версиях единственное заметное различие между локалью и нелокалью в регулярных выражениях должно быть связанным с заражением, если ваш Perl поддерживает проверку заражения (см. perlsec).
Этот модификатор может быть задан по умолчанию use locale, но см. "Какой модификатор набора символов активен?".
/u
означает использовать правила Unicode при сопоставлении шаблонов. На платформах ASCII это означает, что символы с кодами от 128 до 255 приобретают своё значение Latin-1 (ISO-8859-1) (которое такое же, как и в Unicode). (В противном случае Perl считает их значения неопределёнными.) Таким образом, при этом модификаторе платформа ASCII фактически становится платформой Unicode; и, следовательно, например, \w будет соответствовать любому из более чем 100_000 символов-слов в Unicode.
В отличие от большинства локалей, которые специфичны для пары язык-страна, Unicode классифицирует все символы, которые являются буквами где-то в мире, как \w. Например, ваша локаль может не считать, что LATIN SMALL LETTER ETH является буквой (если вы не говорите по-исландски), но Unicode считает. Аналогично, все символы, которые являются десятичными цифрами где-то в мире, будут соответствовать \d; это сотни, а не 10, возможных совпадений. И некоторые из этих цифр выглядят как некоторые из 10 ASCII цифр, но обозначают другое число, так что человек мог бы легко подумать, что число является другой величиной, чем на самом деле. Например, BENGALI DIGIT FOUR (U+09EA) очень похож на ASCII DIGIT EIGHT (U+0038), а LEPCHA DIGIT SIX (U+1C46) очень похож на ASCII DIGIT FIVE (U+0035). И, \d+, может соответствовать строкам цифр, которые являются смесью из разных письменных систем, создавая проблему безопасности. Например, мошеннический веб-сайт мог бы отобразить цену чего-либо с использованием U+1C46, и для пользователя это выглядело бы так, что что-то стоило 500 единиц, но на самом деле стоит 600. Браузер, который обеспечивал выполнение скриптов ("Выполнение скриптов") предотвратил бы это мошенническое отображение. "num()" в Unicode::UCD также может быть использован для решения этой проблемы. Или модификатор /a может быть использован для принудительного соответствия \d только ASCII 0 до 9.
Также, при использовании этого модификатора, регистронезависимое сопоставление работает со всем набором символов Юникода. Например, KELVIN SIGN, соответствует буквам "k" и "K"; и LATIN SMALL LIGATURE FF соответствует последовательности "ff", что, если вы не готовы, может показаться шестнадцатеричной константой, представляя еще одну потенциальную проблему безопасности. Подробное обсуждение проблем безопасности Юникода см. на странице https://unicode.org/reports/tr36.
Этот модификатор можно указать в качестве значения по умолчанию с помощью use feature 'unicode_strings, use locale ':not_characters', или use v5.12 (или более поздних версий), но см. "Какой модификатор набора символов действует?".
/d
ВАЖНО: Из-за непредсказуемого поведения этого модификатора используйте его только для поддержания странных обратных совместимостей. Используйте функцию unicode_strings в новом коде, чтобы случайно не включить этот модификатор по умолчанию.
Что делает этот модификатор? Он "Зависит"!
Этот модификатор означает использование правил сопоставления, нативных для платформы, за исключением случаев, когда необходимо использовать правила Юникода, как показано ниже:
-
Флаг UTF8 целевой строки UTF8 flag (см. ниже) установлен; или
-
Флаг UTF8 (см. ниже) шаблона UTF8 flag установлен; или
-
В шаблоне явно упоминается код символа, превышающий 255 (скажем, с помощью
\x{100}); или -
В шаблоне используется имя Юникода (
\N{...}); или -
В шаблоне используется свойство Юникода (
\p{...}или\P{...}); или -
В шаблоне используется разрыв Юникода (
\b{...}или\B{...}); или -
В шаблоне используется
"(?[ ])" -
В шаблоне используется
(*script_run: ...)
Что касается ссылок на «флаг UTF8» выше: обычно приложения Perl не должны думать о флаге. Он является частью внутренней реализации Perl, поэтому он может меняться, когда захочет Perl. /d может привести к непредсказуемым результатам. См. "Ошибка Юникода" в perlunicode. Эта ошибка стала довольно печально известной, что привело к другим (без ругательств) названиям для этого модификатора, таким как "Dicey" и "Dodgy".
Вот несколько примеров того, как это работает на платформе ASCII:
$str = "\xDF"; #
utf8::downgrade($str); # $str is not UTF8-flagged.
$str =~ /^\w/; # No match, since no UTF8 flag.
$str .= "\x{0e0b}"; # Now $str is UTF8-flagged.
$str =~ /^\w/; # Match! $str is now UTF8-flagged.
chop $str;
$str =~ /^\w/; # Still a match! $str retains its UTF8 flag. В соответствии с конфигурацией по умолчанию Perl этот модификатор автоматически выбирается по умолчанию, если ни один из других не выбран, поэтому еще одно имя для него (к сожалению) — «По умолчанию».
Всякий раз, когда это возможно, используйте unicode_strings для его настройки в качестве значения по умолчанию.
/a (и /aa)
Этот модификатор означает ограничение ASCII (или безопасный ASCII). Этот модификатор можно удваивать, чтобы усилить его действие.
При одиночном использовании он приводит к тому, что последовательности \d, \s, \w, а также классы символов Posix сопоставляются только в диапазоне ASCII. Таким образом, они возвращаются к своим значениям до версии 5.6 и до появления Юникода. В /a, \d всегда означает точно цифры от "0" до "9"; \s означает пять символов [ \f\n\r\t], и начиная с Perl v5.18, вертикальную табуляцию; \w означает 63 символа [A-Za-z0-9_]; и аналогично, все классы Posix, такие как [[:print:]], сопоставляются только с соответствующими символами в диапазоне ASCII.
Этот модификатор полезен для людей, которые случайным образом используют Юникод и не хотят быть обремененными его сложностями и проблемами безопасности.
С /a, можно написать \d с уверенностью, что он будет соответствовать только символам ASCII, и если возникнет необходимость сопоставления за пределами ASCII, можно использовать \p{Digit} (или \p{Word} для \w). Существуют аналогичные конструкции \p{...}, которые могут сопоставлять символы за пределами ASCII, как пробелы (см. "Whitespace" в perlrecharclass), так и классы Posix (см. "POSIX Character Classes" в perlrecharclass). Таким образом, этот модификатор не означает, что вы не можете использовать Юникод, а означает, что для получения соответствия по Юникоду необходимо использовать конструкцию (\p{}, \P{}), которая сигнализирует о Юникоде.
Как можно было ожидать, этот модификатор заставляет, например, \D означать то же, что и [^0-9]; на самом деле, все символы, не являющиеся ASCII, сопоставляются с \D, \S, и \W. \b по-прежнему означает соответствие на границе между \w и \W, используя определения /a (аналогично для \B).
В противном случае, /a ведет себя как модификатор /u, в этом случае регистронезависимое сопоставление использует правила Юникода; например, "k" будет соответствовать Юникоду \N{KELVIN SIGN} при сопоставлении /i, а символы кодов в диапазоне Latin1, превышающие ASCII, будут иметь правила Юникода, когда дело доходит до регистронезависимого сопоставления.
Чтобы запретить сопоставления ASCII/не-ASCII (например, "k" с \N{KELVIN SIGN}), укажите "a" дважды, например /aai или /aia. (Первый случай "a" ограничивает \d, и т.д., а второй случай добавляет ограничения /i). Однако обратите внимание, что символы кодов вне диапазона ASCII будут использовать правила Юникода для сопоставления /i, поэтому модификатор не ограничивает сопоставление только ASCII; он просто запрещает смешение ASCII и не-ASCII.
В итоге, этот модификатор обеспечивает защиту для приложений, которые не хотят иметь дело со всем Юникодом. Указание его дважды обеспечивает дополнительную защиту.
Этот модификатор может быть установлен в качестве значения по умолчанию с помощью use re '/a' или use re '/aa'. Если вы это сделаете, у вас может возникнуть необходимость явного использования модификатора /u, если в нескольких регулярных выражениях вам потребуются полные правила Юникода (но даже здесь лучше, если все находится под функцией "unicode_strings", вместе с use re '/aa'). Также см. "Какой модификатор набора символов действует?".
Какой модификатор набора символов действует?
Какой из этих модификаторов действует в данный момент в регулярном выражении зависит от довольно сложной системы взаимодействий. Эти взаимодействия разработаны таким образом, что обычно вам об этом не нужно беспокоиться, но этот раздел содержит подробную информацию. Как поясняется ниже в "Расширенные шаблоны", можно явно указать модификаторы, которые применяются только к частям регулярного выражения. Внутренний всегда имеет приоритет над внешними, а применяемый к всему выражению имеет приоритет над любыми значениями по умолчанию, описанными в остальной части этого раздела.
Предикат use re '/foo' может использоваться для установки модификаторов по умолчанию (включая эти) для регулярных выражений, скомпилированных в пределах его области действия. Этот предикат имеет приоритет над другими предикатами, перечисленными ниже, которые также изменяют значения по умолчанию.
В противном случае use locale устанавливает модификатор по умолчанию в /l; а use feature 'unicode_strings, или use v5.12 (или более поздних версий) устанавливают значение по умолчанию в /u если они не находятся в той же области действия, что и use locale или use bytes. (use locale ':not_characters' также устанавливает значение по умолчанию в /u, переопределяя любое простое use locale.) В отличие от упомянутых выше механизмов, они влияют на операции, помимо сопоставления регулярных выражений, и поэтому обеспечивают более согласованные результаты с другими операторами, включая использование \U, \l, и т.д. в заменах.
Если ничто из вышеперечисленного не применимо, по соображениям обратной совместимости, модификатор /d применяется по умолчанию. Поскольку это может привести к непредсказуемым результатам, лучше указать, какой другой набор правил следует использовать.
Поведение модификатора набора символов до Perl 5.14
До версии 5.14 явных модификаторов не было, но /l подразумевался для регулярных выражений, скомпилированных в пределах действия use locale, и /d — в противном случае. Однако интерполяция регулярного выражения в большее регулярное выражение игнорирует исходную компиляцию в пользу того, что действовало во время второй компиляции. Существовало несколько несоответствий (ошибок) с модификатором /d, когда правила Юникода использовались неуместно и наоборот. \p{} не подразумевал правил Юникода, и также не все случаи \N{}, до версии 5.12.
Регулярные выражения
Квантификаторы
Квантификаторы используются, когда определенная часть шаблона должна соответствовать определенному числу (или числам) раз. Если квантификатора нет, количество соответствий равно ровно одному. Признаются следующие стандартные квантификаторы:
* Match 0 or more times
+ Match 1 or more times
? Match 1 or 0 times
{n} Match exactly n times
{n,} Match at least n times
{,n} Match at most n times
{n,m} Match at least n but not more than m times (Если неэкранированная фигурная скобка встречается в контексте, отличном от перечисленных выше квантификаторов, где она не является частью обратной последовательности, например, \x{...}, это либо фатальная синтаксическая ошибка, либо она обрабатывается как обычный символ, обычно с предупреждением об устаревании. Для экранирования ее можно предварять обратной косой чертой ("\{") или заключать в квадратные скобки ("[{]"). Это изменение позволит в будущем расширять синтаксис (например, делать необязательным нижнюю границу квантификатора) и лучше проверять синтаксис квантификаторов).
Квантификатор "*" эквивалентен {0,}, квантификатор "+" — {1,}, а квантификатор "?" — {0,1}. n и m ограничены неотрицательными целочисленными значениями, меньшими предварительно установленного предела, определенного при сборке perl. Обычно это 65534 на наиболее распространенных платформах. Фактический предел можно увидеть в сообщении об ошибке, сгенерированном кодом, например таким:
$_ **= $_ , / {$_} / for 2 .. 42; По умолчанию квантифицированный подшаблон является «жадным», то есть он будет соответствовать максимально возможному количеству раз (с учетом определенного начального расположения), при этом все еще позволяя остальной части шаблона соответствовать. Если требуется соответствие минимальному количеству раз, добавьте после квантификатора "?". Обратите внимание, что значения не меняются, меняется только «жадность»:
*? Match 0 or more times, not greedily
+? Match 1 or more times, not greedily
?? Match 0 or 1 time, not greedily
{n}? Match exactly n times, not greedily (redundant)
{n,}? Match at least n times, not greedily
{,n}? Match at most n times, not greedily
{n,m}? Match at least n but not more than m times, not greedily Обычно, когда квантифицированный подшаблон не позволяет остальной части общего шаблона соответствовать, Perl использует обратную подстановку. Однако такое поведение иногда нежелательно. Поэтому Perl предоставляет форму «поглощающего» квантификатора.
*+ Match 0 or more times and give nothing back
++ Match 1 or more times and give nothing back
?+ Match 0 or 1 time and give nothing back
{n}+ Match exactly n times and give nothing back (redundant)
{n,}+ Match at least n times and give nothing back
{,n}+ Match at most n times and give nothing back
{n,m}+ Match at least n but not more than m times and give nothing back Например,
'aaaa' =~ /a++a/ никогда не будет соответствовать, так как a++ поглотит все "a" в строке и не оставит ни одного для оставшейся части шаблона. Эта функция может быть очень полезной, чтобы дать Perl подсказки о том, где не нужно производить обратную подстановку. Например, типичная проблема «сопоставления строки в двойных кавычках» может быть наиболее эффективно решена, если она записана в виде:
/"(?:[^"\\]++|\\.)*+"/ как мы знаем, если заключительная кавычка не совпадает, возврат назад не поможет. Более подробную информацию см. в независимом подвыражении "(?>pattern)"; притяжательные квантификаторы — всего лишь синтаксический сахар для этой конструкции. Например, вышеприведенный пример также можно записать следующим образом:
/"(?>(?:(?>[^"\\]+)|\\.)*)"/ Обратите внимание, что модификатор притяжательного квантификатора не может быть объединен с модификатором нежадного соответствия. Это бессмысленно. Рассмотрим следующую таблицу эквивалентности:
Illegal Legal
------------ ------
X??+ X{0}
X+?+ X{1}
X{min,max}?+ X{min} Последовательности escape
Поскольку шаблоны обрабатываются как строки с двойными кавычками, также работают следующие:
\t tab (HT, TAB)
\n newline (LF, NL)
\r return (CR)
\f form feed (FF)
\a alarm (bell) (BEL)
\e escape (think troff) (ESC)
\cK control char (example: VT)
\x{}, \x00 character whose ordinal is the given hexadecimal number
\N{name} named Unicode character or character sequence
\N{U+263D} Unicode character (example: FIRST QUARTER MOON)
\o{}, \000 character whose ordinal is the given octal number
\l lowercase next char (think vi)
\u uppercase next char (think vi)
\L lowercase until \E (think vi)
\U uppercase until \E (think vi)
\Q quote (disable) pattern metacharacters until \E
\E end either case modification or quoted section, think vi Подробности см. в "Операторы кавычек и похожих на кавычки" в perlop.
Классы символов и другие специальные escape-последовательности
Кроме того, Perl определяет следующее:
Sequence Note Description
[...] [1] Match a character according to the rules of the
bracketed character class defined by the "...".
Example: [a-z] matches "a" or "b" or "c" ... or "z"
[[:...:]] [2] Match a character according to the rules of the POSIX
character class "..." within the outer bracketed
character class. Example: [[:upper:]] matches any
uppercase character.
(?[...]) [8] Extended bracketed character class
\w [3] Match a "word" character (alphanumeric plus "_", plus
other connector punctuation chars plus Unicode
marks)
\W [3] Match a non-"word" character
\s [3] Match a whitespace character
\S [3] Match a non-whitespace character
\d [3] Match a decimal digit character
\D [3] Match a non-digit character
\pP [3] Match P, named property. Use \p{Prop} for longer names
\PP [3] Match non-P
\X [4] Match Unicode "eXtended grapheme cluster"
\1 [5] Backreference to a specific capture group or buffer.
'1' may actually be any positive integer.
\g1 [5] Backreference to a specific or previous group,
\g{-1} [5] The number may be negative indicating a relative
previous group and may optionally be wrapped in
curly brackets for safer parsing.
\g{name} [5] Named backreference
\k<name> [5] Named backreference
\k'name' [5] Named backreference
\k{name} [5] Named backreference
\K [6] Keep the stuff left of the \K, don't include it in $&
\N [7] Any character but \n. Not affected by /s modifier
\v [3] Vertical whitespace
\V [3] Not vertical whitespace
\h [3] Horizontal whitespace
\H [3] Not horizontal whitespace
\R [4] Linebreak - [1]
-
Подробности см. в "Заключенные в квадратные скобки классы символов" в perlrecharclass.
- [2]
-
Подробности см. в "Классы символов POSIX" в perlrecharclass.
- [3]
-
Подробности см. в "Свойства символов Unicode" в perlunicode.
- [4]
-
Подробности см. в "Разное" в perlrebackslash.
- [5]
-
Подробности см. в разделе "Группы захвата" ниже.
- [6]
-
Подробности см. в разделе "Расширенные шаблоны" ниже.
- [7]
-
Обратите внимание, что
\Nимеет два значения. Когда он имеет вид\N{NAME}, он соответствует символу или последовательности символов, имя которого — NAME; аналогично, когда он имеет вид\N{U+hex}, он соответствует символу, чей код Unicode — hex. В противном случае он соответствует любому символу, кроме\n. - [8]
-
Подробности см. в "Расширенные классы символов в квадратных скобках" в perlrecharclass.
Утверждения
Помимо "^" и "$", Perl определяет следующие утверждения нулевой ширины:
\b{} Match at Unicode boundary of specified type
\B{} Match where corresponding \b{} doesn't match
\b Match a \w\W or \W\w boundary
\B Match except at a \w\W or \W\w boundary
\A Match only at beginning of string
\Z Match only at end of string, or before newline at the end
\z Match only at end of string
\G Match only at pos() (e.g. at the end-of-match position
of prior m//g) Граница Unicode (\b{}), доступная начиная с версии v5.22, — это место между двумя символами, или перед первым символом в строке, или после последнего символа в строке, где выполняются определенные критерии, определенные Unicode. Подробности см. в "\b{}, \b, \B{}, \B" в perlrebackslash.
Граница слова (\b) — это место между двумя символами, на одной стороне которого находится \w, а на другой — \W (в любом порядке), учитывая воображаемые символы в начале и конце строки как соответствующие \W. (В классах символов \b представляет собой backspace, а не границу слова, как обычно в любой строке с двойными кавычками.) \A и \Z аналогичны "^" и "$", за исключением того, что они не будут соответствовать несколько раз при использовании модификатора /m, в то время как "^" и "$" будут соответствовать каждой внутренней границе строки. Чтобы соответствовать фактическому концу строки и не игнорировать необязательную завершающую новую строку, используйте \z.
Утверждение \G может быть использовано для цепочки глобальных совпадений (используя m//g), как описано в "Операторы кавычек для регулярных выражений" в perlop. Он также полезен при написании сканеров типа lex, когда у вас есть несколько шаблонов, которые вы хотите сопоставить с последовательными подстроками вашей строки; см. предыдущую ссылку. Фактическое положение, где \G будет соответствовать, также может быть изменено с помощью pos() в качестве lvalue: см. "pos" в perlfunc. Обратите внимание, что правило для соответствий нулевой длины (см. "Повторные шаблоны, соответствующие подстроке нулевой длины") несколько изменяется, при этом содержимое слева от \G не учитывается при определении длины совпадения. Таким образом, следующее не будет соответствовать вечно:
my $string = 'ABC';
pos($string) = 1;
while ($string =~ /(.\G)/g) {
print $1;
} Будет напечатано 'A', а затем программа завершится, так как совпадение считается нулевой ширины и, следовательно, не будет соответствовать в одном и том же положении дважды подряд.
Стоит отметить, что \G при неправильном использовании может привести к бесконечной петле. Будьте внимательны при использовании шаблонов, которые включают \G в чередовании.
Также обратите внимание, что s/// откажется от перезаписи части подстановки, которая уже была заменена; таким образом, например, это остановится после первой итерации, а не будет перебирать строку в обратном направлении:
$_ = "123456789";
pos = 6;
s/.(?=.\G)/X/g;
print; # prints 1234X6789, not XXXXX6789 Группы захвата
Конструктор группирования ( ... ) создает группы захвата (также называемые буферами захвата). Чтобы сослаться на текущее содержимое группы позже, в том же шаблоне, используйте \g1 (или \g{1}) для первой, \g2 (или \g{2}) для второй и так далее. Это называется обратной ссылкой. Нет ограничений на количество подстрок, которые вы можете захватить. Группы нумеруются, начиная с левой открытой скобки, которая имеет номер 1, и так далее. Если группа не соответствует, соответствующая обратная ссылка тоже не будет соответствовать. (Это может произойти, если группа необязательна или в другом ответвлении чередования.) Вы можете опустить "g", и написать "\1", и так далее, но с этим форматом есть некоторые проблемы, описанные ниже.
Вы также можете сослаться на группы захвата относительно, используя отрицательное число, так что \g-1 и \g{-1} относятся к непосредственно предшествующей группе захвата, а \g-2 и \g{-2} относятся к группе перед ней. Например:
/
(Y) # group 1
( # group 2
(X) # group 3
\g{-1} # backref to group 3
\g{-3} # backref to group 1
)
/x будет совпадать так же, как /(Y) ( (X) \g3 \g1 )/x. Это позволяет вам интерполировать регулярные выражения в более крупные регулярные выражения и не беспокоиться о пересчете групп захвата.
Вы также можете обойтись без номеров и создать именованные группы захвата. Запись для объявления и ссылки — (?<name>...) и \g{name} соответственно. (Для совместимости с регулярными выражениями .Net, \g{name} также может быть записано как \k{name}, \k<name> или \k'name'.) name не должно начинаться с цифры и не должно содержать дефисов. Когда у разных групп в одном шаблоне одинаковое имя, любая ссылка на это имя подразумевает левую определенную группу. Именованные группы учитываются в абсолютной и относительной нумерации и поэтому также могут быть указаны этими числами. (Возможны вещи с именованными группами захвата, которые в противном случае требовали (??{}).)
Содержимое группы захвата имеет динамический объем и доступно для вас вне шаблона до конца окружающего блока или до следующего успешного совпадения в том же объеме, что произойдет раньше. Подробности см. в "Составные операторы" в perlsyn и "Правила области видимости переменных регулярных выражений" в perlvar.
Вы можете получить доступ к содержимому группы захвата по абсолютному номеру (используя "$1" вместо "\g1", и так далее); или по имени через хеш %+, используя "$+{name}".
Фигурные скобки необходимы при ссылке на именованные группы захвата, но необязательны для абсолютных или относительных пронумерованных. Фигурные скобки безопаснее при создании регулярного выражения путем конкатенации более мелких строк. Например, если у вас есть qr/$a$b/, а $a содержало "\g1", а $b содержало "37", вы получите /\g137/, что, вероятно, не то, что вы имели в виду.
Если вы используете фигурные скобки, вы также можете добавить любое количество пробельных символов (пробел или табуляция) внутри, но рядом с фигурными скобками, например \g{ -1 } или \k{ name }.
Записи \g и \k были введены в Perl 5.10.0. До этого времени именованные и относительные пронумерованные группы захвата отсутствовали. Абсолютно пронумерованные группы обозначались с помощью \1, \2, и так далее, и эта запись все еще поддерживается (и, вероятно, всегда будет). Но это приводит к некоторым неоднозначностям, если есть более 9 групп захвата, поскольку \10 может обозначать либо десятую группу захвата, либо символ, чья позиция в восьмеричном формате — 010 (backspace в ASCII). Perl устраняет эту неоднозначность, интерпретируя \10 как обратную ссылку только в том случае, если перед ним открыто не менее 10 левых скобок. Аналогично, \11 — это обратная ссылка только в том случае, если перед ней открыто не менее 11 левых скобок. И так далее. \1 и \9 всегда интерпретируются как обратные ссылки. Ниже приведены несколько примеров, которые иллюстрируют эти опасности. Вы можете избежать неоднозначности, всегда используя \g{} или \g, если вы имеете в виду группы захвата; и для восьмеричных констант всегда использовать \o{}, или для \077 и ниже использовать 3 цифры, заполненные ведущими нулями, так как ведущий ноль подразумевает восьмеричную константу.
Запись \digit также работает в определенных условиях вне шаблона. Подробности см. в "Предупреждение об использовании \1 вместо $1" ниже.
Примеры:
s/^([^ ]*) *([^ ]*)/$2 $1/; # swap first two words
/(.)\g1/ # find first doubled char
and print "'$1' is the first doubled character\n";
/(?<char>.)\k<char>/ # ... a different way
and print "'$+{char}' is the first doubled character\n";
/(?'char'.)\g1/ # ... mix and match
and print "'$1' is the first doubled character\n";
if (/Time: (..):(..):(..)/) { # parse out values
$hours = $1;
$minutes = $2;
$seconds = $3;
}
/(.)(.)(.)(.)(.)(.)(.)(.)(.)\g10/ # \g10 is a backreference
/(.)(.)(.)(.)(.)(.)(.)(.)(.)\10/ # \10 is octal
/((.)(.)(.)(.)(.)(.)(.)(.)(.))\10/ # \10 is a backreference
/((.)(.)(.)(.)(.)(.)(.)(.)(.))\010/ # \010 is octal
$a = '(.)\1'; # Creates problems when concatenated.
$b = '(.)\g{1}'; # Avoids the problems.
"aa" =~ /${a}/; # True
"aa" =~ /${b}/; # True
"aa0" =~ /${a}0/; # False!
"aa0" =~ /${b}0/; # True
"aa\x08" =~ /${a}0/; # True!
"aa\x08" =~ /${b}0/; # False Несколько специальных переменных также ссылаются на части предыдущего совпадения. $+ возвращает то, на что соответствовала последняя заключительная скобка. $& возвращает всю сопоставленную строку. (В какой-то момент $0 тоже, но сейчас она возвращает имя программы.) $` возвращает все, что находится перед сопоставленной строкой. $' возвращает все, что находится после сопоставленной строки. А $^N содержит то, что было сопоставлено самой недавно закрытой группой (подстрокой). $^N можно использовать в расширенных шаблонах (см. ниже), например, чтобы присвоить подстроку переменной.
Эти специальные переменные, такие как хеш %+ и пронумерованные переменные совпадения ($1, $2, $3, и так далее), имеют динамический объем до конца окружающего блока или до следующего успешного совпадения, что произойдет раньше. (См. "Составные операторы" в perlsyn.)
Массив @{^CAPTURE} может быть использован для доступа ко ВСЕМ буферам захвата как к массиву без необходимости знать, сколько их. Например
$string=~/$pattern/ and @captured = @{^CAPTURE}; поместит копию каждой переменной захвата, $1, $2 и т. д., в массив @captured.
Обратите внимание, что при интерполяции индекса массива @{^CAPTURE} необходимо использовать обозначение с фигурными скобками:
print "@{^CAPTURE[0]}"; См. "Обозначенные имена переменных с помощью фигурных скобок" в perldata для получения дополнительной информации об этом обозначении.
ПРИМЕЧАНИЕ: Неудачные совпадения в Perl не сбрасывают переменные совпадения, что упрощает написание кода, проверяющего серию более конкретных случаев и запоминающего лучшее совпадение.
ПРЕДУПРЕЖДЕНИЕ: Если ваш код будет выполняться на Perl 5.16 или более ранней версии, имейте в виду, что как только Perl увидит необходимость в $&, $`, или $' в программе, он должен будет предоставить их для каждого поиска по шаблону. Это может существенно замедлить вашу программу.
Perl использует тот же механизм для производства $1, $2, и т.д., поэтому вы также платите за каждый шаблон, содержащий группирующие скобки. (Чтобы избежать этой стоимости, сохранив при этом поведение группирования, используйте расширенное регулярное выражение (?: ... ) вместо него.) Но если вы никогда не используете $&, $` или $', то шаблоны без группирующих скобок не будут наказываться. Поэтому избегайте $&, $', и $`, если можете, но если не можете (и некоторые алгоритмы их действительно ценят), после того как вы использовали их один раз, используйте их свободно, потому что вы уже заплатили за это.
Perl 5.16 ввёл немного более эффективный механизм, который отдельно отмечает, были ли замечены $`, $&, и $', и, таким образом, может потребоваться скопировать только часть строки. Perl 5.20 представил гораздо более эффективный механизм копирования по требованию, который устраняет любые задержки.
В качестве ещё одного обходного пути этой проблемы Perl 5.10.0 представил ${^PREMATCH}, ${^MATCH} и ${^POSTMATCH}, которые эквивалентны $`, $& и $', за исключением того, что они гарантированно определены только после успешного совпадения, выполненного с модификатором /p (сохранение). Использование этих переменных не несёт глобальной нагрузки на производительность, в отличие от их эквивалентов с символами пунктуации, однако с той жертвой, что вам нужно указать Perl, когда вы хотите их использовать. Начиная с Perl 5.20, эти три переменные эквивалентны $`, $& и $', и /p игнорируется.
Квалификация метасимволов
Обрамлённые обратным слэшем метасимволы в Perl являются буквенно-цифровыми, например \b, \w, \n. В отличие от некоторых других языков регулярных выражений, нет ни одного символа с обратным слэшем, который не является буквенно-цифровым. Поэтому всё, что похоже на \\, \(, \), \[, \], \{, или \}, всегда интерпретируется как буквальный символ, а не как метасимвол. Раньше это использовалось в распространённом приёме для отключения или квалификации специального значения метасимволов регулярных выражений в строке, которую вы хотите использовать для шаблона. Просто укажите все символы, не являющиеся "словами":
$pattern =~ s/(\W)/\\$1/g; (Если use locale установлено, то это зависит от текущего локализованного языка.) Сегодня чаще используется функция quotemeta() или последовательность метаквалификации \Q для отключения всех специальных значений метасимволов, как в этом примере:
/$unquoted\Q$quoted\E$unquoted/ Обратите внимание, что если вы помещаете буквальные обратные слэши (те, которые не находятся внутри интерполированных переменных) между \Q и \E, интерполяция обратного слэша с двойной цитатой может привести к путанице. Если вам необходимо использовать буквальные обратные слэши внутри \Q...\E, обратитесь к "Gory details of parsing quoted constructs" в perlop.
quotemeta() и \Q полностью описаны в "quotemeta" в perlfunc.
Расширенные шаблоны
Perl также определяет согласованную синтаксическую расширение для функций, отсутствующих в стандартных инструментах, таких как awk и lex. Синтаксис для большинства из них - пара скобок с вопросительным знаком в качестве первого элемента внутри скобок. Символ после вопросительного знака указывает расширение.
Вопросительный знак был выбран для этого и для конструкции минимального сопоставления, потому что 1) вопросительные знаки редки в старых регулярных выражениях, и 2) всякий раз, когда вы видите один, вы должны остановиться и "задать вопрос", что происходит. Это психология....
-
(?#text) -
Комментарий. Текст текст игнорируется. Обратите внимание, что Perl закрывает комментарий, как только видит
")", поэтому нет способа поместить буквальный")"в комментарий. Закрывающий разделитель шаблона необходимо экранировать обратной косой чертой, если он встречается в комментарии.См. "/x" для другого способа добавления комментариев в шаблоны.
Обратите внимание, что комментарий может быть размещен практически где угодно, кроме середины последовательности экранирования. Примеры:
qr/foo(?#comment)bar/' # Matches 'foobar' # The pattern below matches 'abcd', 'abccd', or 'abcccd' qr/abc(?#comment between literal and its quantifier){1,3}d/ # The pattern below generates a syntax error, because the '\p' must # be followed immediately by a '{'. qr/\p(?#comment between \p and its property name){Any}/ # The pattern below generates a syntax error, because the initial # '\(' is a literal opening parenthesis, and so there is nothing # for the closing ')' to match qr/\(?#the backslash means this isn't a comment)p{Any}/ # Comments can be used to fold long patterns into multiple lines qr/First part of a long regex(?# )remaining part/ -
(?adlupimnsx-imnsx) -
(?^alupimnsx) -
Ноль или более встроенных модификаторов соответствия шаблонам, которые будут включены (или выключены, если предшествует
"-") для остальной части шаблона или остальной части вложенной группы шаблонов (если таковая имеется).Это особенно полезно для динамически сгенерированных шаблонов, таких как те, которые считываются из файла конфигурации, взяты из аргумента или указаны в таблице где-нибудь. Рассмотрим случай, когда некоторые шаблоны должны быть чувствительными к регистру, а некоторые — нет: для шаблонов, нечувствительных к регистру, достаточно включить
(?i)в начало шаблона. Например:$pattern = "foobar"; if ( /$pattern/i ) { } # more flexible: $pattern = "(?i)foobar"; if ( /$pattern/ ) { }Эти модификаторы восстанавливаются в конце вложенной группы. Например,
( (?i) blah ) \s+ \g1будет соответствовать
blahв любом регистре, нескольким пробелам и точной (включая регистр!) повторённому предыдущему слову, при условии модификатора/xи отсутствии модификатора/iвне этой группы.Эти модификаторы не переносятся в именованные подшаблоны, вызываемые во вложенной группе. Другими словами, шаблон, такой как
((?i)(?&NAME))не изменяет чувствительность к регистру шаблона NAME.Модификатор перекрывается последующими появлениями этого конструкта в том же объёме, содержащем тот же модификатор, так что
/((?im)foo(?-m)bar)/соответствует всему
foobarбез учёта регистра, но использует правила/mтолько для частиfoo. Флаг"a"перекрываетaa, аналогичноaaперекрывает"a". То же самое относится к"x"иxx. Следовательно, в/(?-x)foo/xxоба
/xи/xxвыключены во время сопоставленияfoo. А в/(?x)foo/x/xно НЕ/xxвключены для сопоставленияfoo. (Можно ошибочно предположить, что так как внутренний(?x)уже находится в объёме действия/x, что результат фактически будет суммой их, давая/xx. Это не так.) Аналогично, выполнение чего-либо вроде(?xx-x)fooвыключает всё поведение"x"для сопоставленияfoo, это не означает вычитания 1"x"из 2, чтобы получить оставшиеся 1"x".Любой из этих модификаторов может быть установлен для глобального применения ко всем регулярным выражениям, скомпилированным в объёме действия
use re. См. "'/flags' mode" в re.Начиная с Perl 5.14,
"^"(крышка или акцент циркумфлекса) сразу после"?"— это краткое эквивалентное представлениеd-imnsx. Флаги (кроме"d") могут следовать за крышкой для их переопределения. Но знак минус с ней не разрешён.Обратите внимание, что модификаторы
"a","d","l","p"и"u"являются особыми, поскольку их можно только включить, а не выключить, а модификаторы"a","d","l"и"u"взаимоисключающие: указание одного исключает другие, и может появиться не более одного (или двух"a"). Таким образом, например,(?-p)выведет предупреждение при компиляции вuse warnings;(?-d:...)и(?dl:...)— это фатальные ошибки.Также обратите внимание, что модификатор
"p"является особым в том, что его присутствие где-либо в шаблоне имеет глобальное действие.Отсутствие модификаторов делает это операцией без действия (так зачем вы это указали, если это не сгенерированный код?), а начиная с v5.30, предупреждает в
use re 'strict'. -
(?:pattern) -
(?adluimnsx-imnsx:pattern) -
(?^aluimnsx:pattern) -
Это для группировки, а не захвата; оно группирует подвыражения, как
"()", но не создаёт обратных ссылок, как"()". Поэтому@fields = split(/\b(?:a|b|c)\b/)соответствует тем же разделителям полей, что и
@fields = split(/\b(a|b|c)\b/)но не выводит сами разделители как дополнительные поля (хотя такое поведение есть у "split" в perlfunc, когда его шаблон содержит группы захвата). Также это быстрее, если вам не нужно захватывать символы.
Любые буквы между
"?"и":"действуют как модификаторы флагов, как и(?adluimnsx-imnsx). Например,/(?s-i:more.*than).*million/iэквивалентно более подробному
/(?:(?s-i)more.*than).*million/iОбратите внимание, что любые
()конструкции, заключенные в эту, всё равно будут захватывать, если модификатор/nне используется.Как и конструкция "(?adlupimnsx-imnsx)",
aaи"a"перекрывают друг друга, как иxxи"x". Они не являются аддитивными. Таким образом, выполнение чего-либо вроде(?xx-x:foo)выключает всё поведение"x"для сопоставленияfoo.Начиная с Perl 5.14,
"^"(крышка или акцент циркумфлекса) сразу после"?"— это краткое эквивалентное представлениеd-imnsx. Любые положительные флаги (кроме"d") могут следовать за крышкой, поэтому(?^x:foo)эквивалентно
(?x-imns:foo)Крышка сообщает Perl, что эта группа не наследует флаги какого-либо окружающего шаблона, но использует системные значения по умолчанию (
d-imnsx), изменённые любыми указанными флагами.Крышка позволяет упростить строковое представление скомпилированных регулярных выражений. Они выглядят как
(?^:pattern)с любыми нестандартными флагами, появляющимися между крышкой и двоеточием. Тест, который рассматривает такое строковое представление, поэтому не должен иметь в жёстко закодированных системных значениях по умолчанию флагов, только крышку. Если в Perl будут добавлены новые флаги, смысл расширения крышки изменится, чтобы включить значение по умолчанию для этих флагов, поэтому тест по-прежнему будет работать без изменений.
Указание отрицательного флага после крышки является ошибкой, так как флаг избыточен.
Мнемоника для
(?^...): Свежая точка отсчёта, так как обычное использование крышки — это соответствие в начале. -
(?|pattern) -
Это шаблон «сброса ветви», который имеет особую функцию, что группы захвата нумеруются с той же начальной точки в каждом альтернативном ветвлении. Он доступен, начиная с perl 5.10.0.
Группы захвата нумеруются слева направо, но внутри этого конструкта нумерация перезапускается для каждой ветви.
Нумерация внутри каждой ветви будет нормальной, и любые группы, следующие за этим конструктом, будут пронумерованы так, как будто конструкция содержит только одну ветвь, которая будет содержать больше всего групп захвата в ней.
Этот конструкт полезен, когда вы хотите захватить одно из ряда альтернативных соответствий.
Рассмотрим следующий шаблон. Цифры ниже показывают, в какой группе будет храниться захваченное содержимое.
# before ---------------branch-reset----------- after / ( a ) (?| x ( y ) z | (p (q) r) | (t) u (v) ) ( z ) /x # 1 2 2 3 2 3 4Будьте осторожны при использовании шаблона сброса ветви в сочетании с именованными захватами. Именованные захваты реализуются как псевдонимы пронумерованных групп, содержащих захваты, и это мешает реализации шаблона сброса ветви. Если вы используете именованные захваты в шаблоне сброса ветви, лучше использовать те же имена в том же порядке в каждой из альтернатив:
/(?| (?<a> x ) (?<b> y ) | (?<a> z ) (?<b> w )) /xЕсли этого не сделать, могут возникнуть неожиданности:
"12" =~ /(?| (?<a> \d+ ) | (?<b> \D+))/x; say $+{a}; # Prints '12' say $+{b}; # *Also* prints '12'.Проблема здесь в том, что обе группы, именованные
aиb, являются псевдонимами группы, принадлежащей$1. - Утверждения о поиске
-
Утверждения lookaround — это шаблоны нулевой ширины, которые соответствуют определённому шаблону, не включая его в
$&. Положительные утверждения соответствуют, когда их подшаблон соответствует, отрицательные утверждения соответствуют, когда их подшаблон не соответствует. Lookbehind соответствует тексту до текущей позиции совпадения, lookahead соответствует тексту после текущей позиции совпадения.-
(?=pattern) -
(*pla:pattern) -
(*positive_lookahead:pattern) -
Утверждение положительного lookahead нулевой ширины. Например,
/\w+(?=\t)/соответствует слову, за которым следует табуляция, без включения табуляции в$&. -
(?!pattern) -
(*nla:pattern) -
(*negative_lookahead:pattern) -
Утверждение отрицательного lookahead нулевой ширины. Например
/foo(?!bar)/соответствует любому вхождению "foo", за которым не следует "bar". Однако обратите внимание, что lookahead и lookbehind — это НЕ одно и то же. Вы не можете использовать это для lookbehind.Если вы ищете "bar", за которым не предшествует "foo", то
/(?!foo)bar/не сделает того, что вы хотите. Это потому, что(?!foo)просто говорит, что следующее не может быть "foo" — а это не так, это "bar", поэтому "foobar" будет соответствовать. Используйте lookbehind вместо этого (см. ниже). -
(?<=pattern) -
\K -
(*plb:pattern) -
(*positive_lookbehind:pattern) -
Утверждение положительного lookbehind нулевой ширины. Например,
/(?<=\t)\w+/соответствует слову, которое следует за табуляцией, без включения табуляции в$&.До Perl 5.30 он работал только с lookbehind фиксированной ширины, но начиная с этой версии он может обрабатывать переменную длину от 1 до 255 символов в качестве экспериментальной функции. Эта функция включается автоматически, если вы используете утверждение положительного lookbehind переменной длины.
В Perl 5.35.10 область экспериментального характера этого конструкта была сужена, и предупреждения о экспериментальном характере будут выдаваться только при наличии в конструкте захватывающих скобок. Предупреждения будут выводиться во время компиляции шаблона, если они не отключены, в категории
experimental::vlb. Это для предупреждения о том, что точное содержимое буферов захвата в lookbehind переменной длины не определено и может быть изменено в будущей версии Perl.В настоящее время, если вы используете буферы захвата внутри положительного lookbehind переменной длины, результат будет самым длинным и, следовательно, самым левым возможным совпадением. Это означает, что
"aax" =~ /(?=x)(?<=(a|aa))/ "aax" =~ /(?=x)(?<=(aa|a))/ "aax" =~ /(?=x)(?<=(a{1,2}?)/ "aax" =~ /(?=x)(?<=(a{1,2})/все приведут к тому, что
$1будет содержать"aa". Возможно, в будущей версии Perl мы изменим это поведение.Существует специальная форма этого конструкта, называемая
\K(доступна с Perl 5.10.0), которая заставляет движок регулярных выражений «сохранять» всё, что было сопоставлено до\Kи не включать его в$&. Это эффективно обеспечивает lookbehind переменной длины любой длины без экспериментальных ограничений.И существует техника, которая может быть использована для обработки lookbehind переменной длины в более ранних версиях и длиной более 255 символов. Она описана в http://www.drregex.com/2019/02/variable-length-lookbehinds-actually.html.
Обратите внимание, что в
/i, несколько одиночных символов соответствуют двум или трём другим символам. Это делает их переменной длины, и длина 255 относится к максимальному числу символов в совпадении. Например,qr/\N{LATIN SMALL LETTER SHARP S}/iсоответствует последовательности"ss". Ваше утверждение lookbehind может содержать 127 символов Sharp S в/i, но добавление 128-го приведет к ошибке компиляции, поскольку это может соответствовать 256"s"символам подряд.Использование
\Kвнутри другого утверждения lookaround разрешено, но поведение в настоящее время не определено.По различным причинам
\Kможет быть значительно эффективнее, чем эквивалентный(?<=...)конструкт, и он особенно полезен в ситуациях, когда вам нужно эффективно удалить что-то, следующее за чем-то ещё в строке. Напримерs/(foo)bar/$1/g;может быть переписано как гораздо более эффективное
s/foo\Kbar//g;Использование модификатора нежелательности
"?"может не дать ожидаемых результатов, если он находится внутри захватывающей группы в конструкте. -
(?<!pattern) -
(*nlb:pattern) -
(*negative_lookbehind:pattern) -
Утверждение отрицательного lookbehind нулевой ширины. Например,
/(?<!bar)foo/соответствует любому вхождению "foo", за которым не следует "bar".До Perl 5.30 он работал только с lookbehind фиксированной ширины, но начиная с этой версии он может обрабатывать переменную длину от 1 до 255 символов в качестве экспериментальной функции. Эта функция включается автоматически, если вы используете утверждение отрицательного lookbehind переменной длины.
В Perl 5.35.10 область экспериментального характера этого конструкта была сужена, и предупреждения о экспериментальном характере будут выдаваться только при наличии в конструкте захватывающих скобок. Предупреждения будут выводиться во время компиляции шаблона, если они не отключены, в категории
experimental::vlb. Это для предупреждения о том, что точное содержимое буферов захвата в lookbehind переменной длины не определено и может быть изменено в будущей версии Perl.В настоящее время, если вы используете буферы захвата внутри отрицательного lookbehind переменной длины, результат может не быть тем, чего вы ожидаете, например:
say "axfoo"=~/(?=foo)(?<!(a|ax)(?{ say $1 }))/ ? "y" : "n";выведет следующее:
a noчто не имеет смысла, так как это должно напечатать "ax", так как "a" не выстраивается в правильном месте. Ещё один пример:
say "yes: '$1-$2'" if "aayfoo"=~/(?=foo)(?<!(a|aa)(a|aa)x)/;выведет следующее:
yes: 'aa-a'Возможно, в будущей версии Perl мы изменим это поведение, чтобы оба этих примера давали более осмысленный вывод.
Мы уверены, что конструкт будет соответствовать и отклонять шаблоны должным образом, неопределённое поведение напрямую связано со значением буфера захвата во время или после сопоставления.
Существует техника, которая может быть использована для обработки lookbehind переменной длины в более ранних версиях и длиной более 255 символов. Она описана в http://www.drregex.com/2019/02/variable-length-lookbehinds-actually.html.
Обратите внимание, что в
/i, несколько одиночных символов соответствуют двум или трём другим символам. Это делает их переменной длины, и длина 255 относится к максимальному числу символов в совпадении. Например,qr/\N{LATIN SMALL LETTER SHARP S}/iсоответствует последовательности"ss". Ваше утверждение lookbehind может содержать 127 символов Sharp S в/i, но добавление 128-го приведет к ошибке компиляции, поскольку это может соответствовать 256"s"символам подряд.Использование модификатора нежелательности
"?"может не дать ожидаемых результатов, если он находится внутри захватывающей группы в конструкте. -
(?<NAME>pattern) -
(?'NAME'pattern) -
Именованная группа захвата. Абсолютно идентична обычным захватывающим скобкам
()за исключением того, что к группе можно обратиться по имени в различных конструкциях регулярных выражений (например,\g{NAME}) и получить доступ к ней по имени после успешного сопоставления через%+или%-. См. perlvar для получения более подробной информации о массивах%+и%-.Если у нескольких различных захватывающих групп одинаковое имя, то
$+{NAME}будет ссылаться на самую левую определённую группу в совпадении.Формы
(?'NAME'pattern)и(?<NAME>pattern)эквивалентны.ПРИМЕЧАНИЕ: Хотя обозначение этого конструкта совпадает с аналогичной функцией в регулярных выражениях .NET, поведение не совпадает. В Perl группы нумеруются последовательно независимо от того, именованные они или нет. Таким образом, в шаблоне
/(x)(?<foo>y)(z)/$+{foo}будет таким же, как$2, а$3будет содержать 'z' вместо обратного, чего может ожидать пользователь .NET регулярных выражений.В настоящее время NAME ограничено только простыми идентификаторами. Другими словами, он должен соответствовать
/^[_A-Za-z][_A-Za-z0-9]*\z/или его расширению Юникода (см. utf8), хотя он не расширяется локалью (см. perllocale).ПРИМЕЧАНИЕ: Чтобы облегчить программистам с опытом работы с движками регулярных выражений Python или PCRE, шаблон
(?P<NAME>pattern)может использоваться вместо(?<NAME>pattern); однако эта форма не поддерживает использование одинарных кавычек в качестве разделителя для имени. -
\k<NAME> -
\k'NAME' -
\k{NAME} -
Именованная ссылка на обратную ссылку. Аналогично числовым обратным ссылкам, за исключением того, что группа обозначается именем, а не номером. Если у нескольких групп одинаковое имя, то это относится к самой левой определённой группе в текущем совпадении.
Ошибка, если ссылаться на имя, которое не определено с помощью
(?<NAME>)ранее в шаблоне.Все три формы эквивалентны, хотя с
\k{ NAME }, вы можете необязательно иметь пробелы внутри, но рядом со скобками, как показано.ПРИМЕЧАНИЕ: Чтобы облегчить программистам с опытом работы с движками регулярных выражений Python или PCRE, шаблон
(?P=NAME)может использоваться вместо\k<NAME>. -
(?{ code })
-
-
ПРЕДУПРЕЖДЕНИЕ: Для безопасного использования этой функции необходимо понимать её ограничения. Код, выполняемый с побочными эффектами, может работать не одинаково в разных версиях из-за влияния будущих оптимизаций в движке регулярных выражений. Для получения дополнительной информации см. "Частота выполнения встраиваемого кода".
Это утверждение нулевой ширины выполняет любой встраиваемый Perl-код. Оно всегда выполняется успешно, а его возвращаемое значение устанавливается как
$^R.В литеральных шаблонах код анализируется одновременно с окружающим кодом. Внутри шаблона управление временно передаётся обратно парсеру Perl, пока не будет найдена логически соответствующая закрывающая фигурная скобка. Это аналогично тому, как обрабатывается выражение индекса массива в литеральной строке, например
"abc$array[ 1 + f('[') + g()]def"В частности, фигурные скобки не обязательно должны быть сбалансированы:
s/abc(?{ f('{'); })/def/Даже в шаблоне, который интерполируется и компилируется во время выполнения, литеральные блоки кода будут скомпилированы один раз во время компиляции Perl; следующее выводит "ABCD":
print "D"; my $qr = qr/(?{ BEGIN { print "A" } })/; my $foo = "foo"; /$foo$qr(?{ BEGIN { print "B" } })/; BEGIN { print "C" }В шаблонах, где текст кода получен из информации времени выполнения, а не появляется буквально в исходном коде/шаблоне, код компилируется одновременно с компиляцией шаблона, и по соображениям безопасности,
use re 'eval'должен быть в области видимости. Это предотвращает выполнение кодовых фрагментов, предоставляемых пользователем, в шаблонах.В ситуациях, когда вам нужно включить это с помощью
use re 'eval', вы также должны включить проверку загрязнения, если ваш Perl её поддерживает. Ещё лучше использовать тщательно ограниченную оценку внутри безопасного отсека. См. perlsec для получения подробной информации об этих механизмах.С точки зрения анализа, лексической области видимости и замыканий,
/AAA(?{ BBB })CCC/ведет себя примерно как
/AAA/ && do { BBB } && /CCC/Аналогично,
qr/AAA(?{ BBB })CCC/ведет себя примерно как
sub { /AAA/ && do { BBB } && /CCC/ }В частности:
{ my $i = 1; $r = qr/(?{ print $i })/ } my $i = 2; /$r/; # prints "1"Внутри блока
(?{...}),$_ссылается на строку, по которой ищется соответствие регулярным выражением. Вы также можете использоватьpos()для того, чтобы знать текущую позицию соответствия в этой строке.Блок кода вводит новую область видимости с точки зрения объявлений лексических переменных, но не с точки зрения
localи аналогичных локальных поведений. Поэтому последующие блоки кода в том же шаблоне по-прежнему будут видеть значения, которые были локализованы в предыдущих блоках. Эти накопленные локализации отменяются либо в конце успешного соответствия, либо если утверждение отменяется (см. "Обратный откат"). Например,$_ = 'a' x 8; m< (?{ $cnt = 0 }) # Initialize $cnt. ( a (?{ local $cnt = $cnt + 1; # Update $cnt, # backtracking-safe. }) )* aaaa (?{ $res = $cnt }) # On success copy to # non-localized location. >x;сначала увеличит
$cntдо 8; затем во время обратного отката его значение будет уменьшено до 4, что является значением, присвоенным$res. В конце выполнения регулярного выражения$cntбудет уменьшено до его начального значения 0.Это утверждение может быть использовано как условие в
(?(condition)yes-pattern|no-pattern)переключателе. Если оно не используется таким образом, результат оценки code помещается в специальную переменную
$^R. Это происходит немедленно, поэтому$^Rможно использовать из других утверждений(?{ code })внутри одного и того же регулярного выражения.Присваивание переменной
$^Rвыше правильно локализовано, поэтому старое значение$^Rвосстанавливается, если утверждение отменяется; см. "Обратный откат".Обратите внимание, что специальная переменная
$^Nособенно полезна с блоками кода для захвата результатов подстрочных соответствий в переменные без необходимости отслеживать количество вложенных скобок. Например:$_ = "The brown fox jumps over the lazy dog"; /the (\S+)(?{ $color = $^N }) (\S+)(?{ $animal = $^N })/i; print "color = $color, animal = $animal\n";Использование этого конструкта глобально отключает некоторые оптимизации в шаблоне, и в результате шаблон может выполняться гораздо медленнее. Используйте
*, а не блок?, чтобы создать оптимистичную форму этого конструкта.(*{ ... })не должен отключать никаких оптимизаций. -
(*{ code }) -
Это *точно* такое же, как
(?{ code })за исключением того, что оно вообще не отключает никаких оптимизаций в движке регулярных выражений. Частота его выполнения может варьироваться в зависимости от версии Perl. -
(??{ code }) -
ПРЕДУПРЕЖДЕНИЕ: Для безопасного использования этой функции необходимо понимать её ограничения. Код, выполняемый с побочными эффектами, может работать не одинаково в разных версиях из-за влияния будущих оптимизаций в движке регулярных выражений. Для получения дополнительной информации см. "Частота выполнения встраиваемого кода".
Это "отложенное" подвыражение регулярного выражения. Оно ведет себя *точно* так же, как блок кода
(?{ code }), описанный выше, за исключением того, что его возвращаемое значение, вместо того, чтобы быть присвоенным переменной$^R, обрабатывается как шаблон, компилируется, если это строка (или используется как есть, если это объект qr//), затем сопоставляется так, как если бы этот конструкт был вставлен.Во время сопоставления этого подшаблона у него есть свой набор захватов, которые действительны во время подсопоставления, но отбрасываются, как только управление возвращается к основному шаблону. Например, следующее соответствует, при этом внутренний шаблон захватывает "B" и соответствует "BB", а внешний шаблон захватывает "A";
my $inner = '(.)\1'; "ABBA" =~ /^(.)(??{ $inner })\1/; print $1; # prints "A";Обратите внимание, что это означает, что внутренний шаблон не может обратиться к группе захвата, определенной снаружи. (Сам блок кода может использовать
$1, и т.д., для обращения к группам захвата внешнего шаблона). Таким образом, хотя('a' x 100)=~/(??{'(.)' x 100})/будет соответствовать, он не будет устанавливать
$1при выходе.Следующий шаблон соответствует скобке:
$re = qr{ \( (?: (?> [^()]+ ) # Non-parens without backtracking | (??{ $re }) # Group with matching parens )* \) }x;См. также
(?PARNO)для другого, более эффективного способа достижения той же цели.Выполнение отложенного регулярного выражения слишком много раз без потребления входной строки также приведет к ошибке.
Использование этого конструкта глобально отключает некоторые оптимизации в шаблоне, и в результате шаблон может выполняться значительно медленнее.
-
(?PARNO)(?-PARNO)(?+PARNO)(?R)(?0) -
Рекурсивный подшаблон. Обработайте содержимое заданного буфера захвата в текущем шаблоне как независимый подшаблон и попытайтесь сопоставить его в текущей позиции в строке. Подшаблону доступна информация о состоянии захвата от вызывающего элемента для таких вещей, как обратные ссылки, но буферы захвата, заданные подшаблоном, не видны вызывающему элементу.
Аналогично
(??{ code }), за исключением того, что оно не включает выполнение какого-либо кода или потенциальную компиляцию возвращаемой строки шаблона; вместо этого оно обрабатывает часть текущего шаблона, содержащуюся в заданной группе захвата, как независимый шаблон, который должен соответствовать в текущей позиции. Отличие также в обработке буферов захвата, в отличие от(??{ code }), рекурсивные шаблоны имеют доступ к состоянию соответствия своего вызывающего элемента, поэтому можно безопасно использовать обратные ссылки.PARNO — это последовательность цифр (не начинающаяся с 0), значение которой отражает номер скобки захватывающей группы для рекурсии.
(?R)выполняет рекурсию в начало всего шаблона.(?0)— это альтернативный синтаксис для(?R). Если PARNO предваряется знаком плюс или минус, предполагается относительное значение, при этом отрицательные числа обозначают предыдущие группы захвата, а положительные — последующие. Таким образом,(?-1)относится к наиболее недавно объявленной группе, а(?+1)указывает на следующую объявленную группу. Обратите внимание, что подсчёт для относительной рекурсии отличается от относительных обратных ссылок, так как с рекурсией не закрытые группы включаются.Следующий шаблон соответствует функции
foo(), которая может содержать сбалансированные скобки в качестве аргумента.$re = qr{ ( # paren group 1 (full function) foo ( # paren group 2 (parens) \( ( # paren group 3 (contents of parens) (?: (?> [^()]+ ) # Non-parens without backtracking | (?2) # Recurse to start of paren group 2 )* ) \) ) ) }x;Если шаблон использовался следующим образом
'foo(bar(baz)+baz(bop))'=~/$re/ and print "\$1 = $1\n", "\$2 = $2\n", "\$3 = $3\n";выход должен быть следующим:
$1 = foo(bar(baz)+baz(bop)) $2 = (bar(baz)+baz(bop)) $3 = bar(baz)+baz(bop)Если соответствующей захватывающей группы нет, это ошибка. Глубокая рекурсия без потребления входной строки также приведет к ошибке.
Следующее демонстрирует, как использование отрицательного индексирования может упростить встраивание рекурсивных шаблонов внутри конструкта
qr//для последующего использования:my $parens = qr/(\((?:[^()]++|(?-1))*+\))/; if (/foo $parens \s+ \+ \s+ bar $parens/x) { # do something here... }Примечание, что этот шаблон не ведет себя так же, как эквивалентный PCRE или Python-конструкт той же формы. В Perl вы можете выполнить обратный откат в рекурсивную группу, в PCRE и Python рекурсивная группа обрабатывается как атомарная. Кроме того, модификаторы решаются во время компиляции, поэтому конструкции, такие как
(?i:(?1))или(?:(?i)(?1))не влияют на то, как будет обрабатываться подшаблон. -
(?&NAME) -
Рекурсия к именованному подшаблону. Идентично
(?PARNO)за исключением того, что скобка для рекурсии определяется по имени. Если несколько скобок имеют одно и то же имя, рекурсия выполняется к самой левой скобке.Ссылка на имя, не объявленное где-либо в шаблоне, является ошибкой.
ПРИМЕЧАНИЕ: Для упрощения работы программистов, знакомых с движками регулярных выражений Python или PCRE, шаблон
(?P>NAME)может быть использован вместо(?&NAME). -
(?(condition)yes-pattern|no-pattern) -
(?(condition)yes-pattern)
-
Условное выражение. Соответствует yes-pattern, если condition имеет истинное значение, и соответствует no-pattern в противном случае. Отсутствующий шаблон всегда соответствует.
(condition)должно быть одним из:- целое число в скобках
-
(что является допустимым, если соответствующая пара скобок совпала);
- утверждение о нулевой ширине с опережающим/опережающим/вычисляемым видом;
- имя в угловых скобках или одинарных кавычках
-
(что является допустимым, если группа с данным именем совпала);
-
специальный символ
(R) -
(истина, когда вычисляется внутри рекурсии или eval). Кроме того,
"R"может следовать за числом (что будет истинно при вычислении во время рекурсии внутри соответствующей группы) или за&NAME, в этом случае оно будет истинным только при вычислении во время рекурсии в указанной группе.
Вот сводка возможных предикатов:
-
(1)(2)... -
Проверяет, совпала ли захваченная группа с номером. Полный синтаксис:
(?(1)then|else) -
(<NAME>)('NAME') -
Проверяет, совпала ли группа с заданным именем. Полный синтаксис:
(?(<name>)then|else) -
(?=...)(?!...)(?<=...)(?<!...) -
Проверяет, соответствует ли шаблон (или не соответствует, для вариантов
"!") . Полный синтаксис:(?(?=lookahead)then|else) -
(?{ CODE }) -
Обрабатывает возвращаемое значение блока кода как условие. Полный синтаксис:
(?(?{ CODE })then|else)Обратите внимание, что использование этой конструкции может глобально повлиять на производительность шаблона. Рассмотрите возможность использования
(*{ CODE }) -
(*{ CODE }) -
Обрабатывает возвращаемое значение блока кода как условие. Полный синтаксис:
(?(*{ CODE })then|else) -
(R) -
Проверяет, вычислялось ли выражение внутри рекурсии. Полный синтаксис:
(?(R)then|else) -
(R1)(R2)... -
Проверяет, вычислялось ли выражение во время непосредственного выполнения внутри n-й захваченной группы. Эта проверка является регулярным выражением, эквивалентным
if ((caller(0))[3] eq 'subname') { ... }Другими словами, она не проверяет всю стек рекурсии.
Полный синтаксис:
(?(R1)then|else) -
(R&NAME) -
Аналогично
(R1), этот предикат проверяет, выполняемся ли мы непосредственно внутри левосторонней группы с заданным именем (этот же принцип логики используется(?&NAME)для устранения неоднозначности). Он не проверяет весь стек, а только имя самой внутренней активной рекурсии. Полный синтаксис:(?(R&name)then|else) -
(DEFINE) -
В этом случае шаблон yes-pattern никогда не выполняется напрямую, и no-pattern не допускается. Похоже по духу на
(?{0}), но эффективнее. Подробности см. ниже. Полный синтаксис:(?(DEFINE)definitions...)
Например:
m{ ( \( )? [^()]+ (?(1) \) ) }xсоответствует блоку, не содержащему скобок, возможно, включенному в сами скобки.
Специальной формой является предикат
(DEFINE), который никогда не выполняет свой шаблон yes-pattern напрямую и не допускает шаблон no-pattern. Это позволяет определить подшаблоны, которые будут выполняться только механизмом рекурсии. Таким образом, вы можете определить набор правил регулярных выражений, которые можно объединить в любой выбранный вами шаблон.Рекомендуется, чтобы для этого использования блок DEFINE находился в конце шаблона, и вы назначали имена любым подшаблонам, определенным в нем.
Кроме того, стоит отметить, что шаблоны, определенные таким образом, вероятно, не будут такими эффективными, так как оптимизатор не очень хорошо обрабатывает их.
Пример использования:
/(?<NAME>(?&NAME_PAT))(?<ADDR>(?&ADDRESS_PAT)) (?(DEFINE) (?<NAME_PAT>....) (?<ADDRESS_PAT>....) )/xОбратите внимание, что захваченные группы, сопоставленные внутри рекурсии, недоступны после возвращения из рекурсии, поэтому необходимо дополнительный уровень захваченных групп. Таким образом,
$+{NAME_PAT}не будет определен, даже если$+{NAME}будет.Наконец, имейте в виду, что подшаблоны, созданные внутри блока DEFINE, учитываются в абсолютном и относительном количестве захватов, поэтому это:
my @captures = "a" =~ /(.) # First capture (?(DEFINE) (?<EXAMPLE> 1 ) # Second capture )/x; say scalar @captures;Выведет 2, а не 1. Это особенно важно, если вы собираетесь скомпилировать определения с оператором
qr//, а затем интерполировать их в другой шаблон. -
(?>pattern) -
(*atomic:pattern) -
«Независимое» подвыражение, которое соответствует подстроке, которую шаблон pattern сопоставил бы, если бы он был закреплён в данной позиции, и оно соответствует только этой подстроке. Эта конструкция полезна для оптимизации того, что в противном случае были бы «вечные» совпадения, потому что она не будет возвращаться назад (см. "Обратный отсчёт"). Она также может быть полезна в тех местах, где желательна семантика «захвата всего, что можно, и не возвращения ничего».
Например:
^(?>a*)abникогда не будет соответствовать, так как(?>a*)(закреплённый в начале строки, как указано выше) будет соответствовать всем символам"a"в начале строки, не оставляя"a"дляabсоответствия. В отличие от этого,a*abбудет соответствовать так же, какa+b, поскольку совпадение подгруппыa*зависит от последующей группыab(см. "Обратный отсчёт"). В частности,a*внутриa*abбудет соответствовать меньшему количеству символов, чем самостоятельноеa*, так как это делает совпадение хвоста.(?>pattern)не отключает обратный отсчёт полностью после соответствия. Возвращение назад по конструкции всё ещё возможно, но не в неё. Так,((?>a*)|(?>b*))arпо-прежнему будет соответствовать «bar».Эффект, аналогичный
(?>pattern), можно получить, написав(?=(pattern))\g{-1}. Это соответствует той же подстроке, что и самостоятельноеa+, а последующее\g{-1}съедает сопоставленную строку; таким образом, он превращает утверждение нулевой длины в аналог(?>...). (Разница между этими двумя конструкциями в том, что вторая использует захваченную группу, таким образом, изменяя порядковые номера обратных ссылок в остальной части регулярного выражения.)Рассмотрим этот шаблон:
m{ \( ( [^()]+ # x+ | \( [^()]* \) )+ \) }xЭто эффективно соответствует непустой группе с совпадающими скобками глубиной не более двух уровней. Однако, если такой группы нет, это займёт практически бесконечно много времени на длинной строке. Это происходит из-за того, что существует так много различных способов разбить длинную строку на несколько подстрок. Именно это делает
(.+)+, а(.+)+подобно подшаблону вышеприведённого шаблона. Подумайте, как вышеуказанный шаблон обнаруживает отсутствие совпадения на((()aaaaaaaaaaaaaaaaaaза несколько секунд, но каждый дополнительный символ удваивает это время. Эта экспоненциальная производительность создаст иллюзию зависания программы. Однако небольшое изменение этого шаблонаm{ \( ( (?> [^()]+ ) # change x+ above to (?> x+ ) | \( [^()]* \) )+ \) }xкоторый использует
(?>...)соответствует точно так же, как и тот, что выше (проверка этого самостоятельно будет продуктивным упражнением), но завершается в четыре раза быстрее, когда используется на подобной строке с 1000000"a". Однако помните, что, когда эта конструкция сопровождается квантификатором, она в настоящее время генерирует сообщение об ошибке в режимеuse warningsили переключателе -w, указывая, что"matches null string many times in regex".В простых группах, таких как шаблон
(?> [^()]+ ), аналогичный эффект может быть достигнут с помощью отрицательного опережающего утверждения, как в[^()]+ (?! [^()] ). Это было только в 4 раза медленнее на строке с 1000000"a".Семантика «захвата всего, что можно, и не возвращения ничего» желательна во многих ситуациях, когда на первый взгляд простая
()*выглядит как правильное решение. Предположим, мы анализируем текст, комментарии в котором разделяются"#"и некоторым необязательным (горизонтальным) пробелом. Вопреки внешнему виду,#[ \t]*не является правильным подвыражением для сопоставления разделителя комментария, поскольку оно может «сдаться» некоторым пробелам, если оставшаяся часть шаблона может быть согласована таким образом. Правильный ответ — один из следующих:(?>#[ \t]*) #[ \t]*(?![ \t])Например, для захвата непустых комментариев в
$1, нужно использовать один из следующих:/ (?> \# [ \t]* ) ( .+ ) /x; / \# [ \t]* ( [^ \t] .* ) /x;Выбор зависит от того, которое из этих выражений лучше отражает вышеизложенное описание комментариев.
В некоторых литературоведческих источниках эта конструкция называется «атомарным соответствием» или «положительным соответствием».
Позитивные квантификаторы эквивалентны помещению элемента, к которому они применяются, в одну из этих конструкций. Следующие эквивалентности применяются:
Quantifier Form Bracketing Form --------------- --------------- PAT*+ (?>PAT*) PAT++ (?>PAT+) PAT?+ (?>PAT?) PAT{min,max}+ (?>PAT{min,max})Вложенные
(?>...)конструкции не являются пустыми операциями, даже если на первый взгляд они таковыми могут показаться. Это связано с тем, что вложенные(?>...)могут ограничивать внутренний обратный отсчёт, который в противном случае мог бы произойти. Например,"abc" =~ /(?>a[bc]*c)/соответствует, но
"abc" =~ /(?>a(?>[bc]*)c)/не соответствует.
-
(?[ ]) -
См. "Расширенные наборы символов в квадратных скобках" в perlrecharclass.
Обратный отсчёт
ПРИМЕЧАНИЕ: Этот раздел представляет абстрактное приближение поведения регулярных выражений. Более строгий (и сложный) взгляд на правила, участвующие в выборе соответствия среди возможных альтернатив, см. "Объединение частей RE".
Основной особенностью сопоставления с регулярными выражениями является понятие «обратного отсчёта», которое в настоящее время используется (при необходимости) всеми квантификаторами регулярных выражений без позитивных вариантов, а именно "*", *?, "+", +?, {n,m}, и {n,m}?. Обратный отсчёт часто оптимизируется внутри, но общий принцип, изложенный здесь, справедлив.
Чтобы регулярное выражение соответствовало, все регулярное выражение должно соответствовать, а не только его часть. Итак, если начало шаблона, содержащего квантификатор, завершается успехом, который заставляет последующие части шаблона потерпеть неудачу, движок сопоставления возвращается назад и пересчитывает начальную часть — вот почему это называется обратным отсчётом.
Вот пример обратного отсчёта: Предположим, что вы хотите найти слово, следующего за «foo», в строке «Food is on the foo table»:
$_ = "Food is on the foo table.";
if ( /\b(foo)\s+(\w+)/i ) {
print "$2 follows $1.\n";
} Когда происходит сопоставление, первая часть регулярного выражения (\b(foo)) находит возможное совпадение в самом начале строки и загружает $1 со значением «Foo». Однако, как только движок сопоставления видит, что после «Foo», которое было сохранено в $1, нет пробелов, он понимает свою ошибку и начинает заново с символа, следующего за тем, где у него было предварительное соответствие. На этот раз он продвигается до следующего вхождения «foo». В этот раз всё регулярное выражение совпадает, и вы получаете ожидаемый результат «table follows foo».
Иногда минимальное соответствие может очень сильно помочь. Представьте, что вы хотите сопоставить всё между «foo» и «bar». Сначала вы напишите что-то вроде этого:
$_ = "The food is under the bar in the barn.";
if ( /foo(.*)bar/ ) {
print "got <$1>\n";
} Что, возможно, неожиданно даёт:
got <d is under the bar in the > Потому что .* был жадным, поэтому вы получите всё между первым "foo" и последним "bar". Здесь эффективнее использовать минимальное соответствие, чтобы убедиться, что вы получите текст между "foo" и первым последующим "bar".
if ( /foo(.*?)bar/ ) { print "got <$1>\n" }
got <d is under the > Вот ещё один пример. Допустим, вы хотите сопоставить число в конце строки, а также сохранить предшествующую часть совпадения. Поэтому вы пишете это:
$_ = "I have 2 numbers: 53147";
if ( /(.*)(\d*)/ ) { # Wrong!
print "Beginning is <$1>, number is <$2>.\n";
} Это вообще не сработает, потому что .* был жадным и проглотил всю строку. Так как \d* может соответствовать пустой строке, полное регулярное выражение успешно сопоставилось.
Beginning is <I have 2 numbers: 53147>, number is <>. Вот некоторые варианты, большинство из которых не работают:
$_ = "I have 2 numbers: 53147";
@pats = qw{
(.*)(\d*)
(.*)(\d+)
(.*?)(\d*)
(.*?)(\d+)
(.*)(\d+)$
(.*?)(\d+)$
(.*)\b(\d+)$
(.*\D)(\d+)$
};
for $pat (@pats) {
printf "%-12s ", $pat;
if ( /$pat/ ) {
print "<$1> <$2>\n";
} else {
print "FAIL\n";
}
} Это выведет:
(.*)(\d*) <I have 2 numbers: 53147> <>
(.*)(\d+) <I have 2 numbers: 5314> <7>
(.*?)(\d*) <> <>
(.*?)(\d+) <I have > <2>
(.*)(\d+)$ <I have 2 numbers: 5314> <7>
(.*?)(\d+)$ <I have 2 numbers: > <53147>
(.*)\b(\d+)$ <I have 2 numbers: > <53147>
(.*\D)(\d+)$ <I have 2 numbers: > <53147> Как видите, это может быть немного сложно. Важно понимать, что регулярное выражение — это всего лишь набор утверждений, которые дают определение успешного совпадения. Может быть 0, 1 или несколько различных способов, которыми это определение может совпасть с конкретной строкой. И если есть несколько способов, которыми это может совпасть, вам нужно понять обратный откат, чтобы знать, какой вариант успеха вы получите.
При использовании утверждений и отрицаний с опережением это может стать ещё сложнее. Представьте, что вы хотите найти последовательность нецифр, за которой не следует "123". Вы можете попробовать записать это как
$_ = "ABC123";
if ( /^\D*(?!123)/ ) { # Wrong!
print "Yup, no 123 in $_\n";
} Но это не совпадёт; по крайней мере, не так, как вы надеетесь. Он утверждает, что в строке нет 123. Вот более чёткое представление о том, почему этот шаблон совпадает, вопреки распространённому мнению:
$x = 'ABC123';
$y = 'ABC445';
print "1: got $1\n" if $x =~ /^(ABC)(?!123)/;
print "2: got $1\n" if $y =~ /^(ABC)(?!123)/;
print "3: got $1\n" if $x =~ /^(\D*)(?!123)/;
print "4: got $1\n" if $y =~ /^(\D*)(?!123)/; Это выводит
2: got ABC
3: got AB
4: got ABC Вы могли ожидать, что тест 3 завершится неудачей, потому что он кажется более универсальной версией теста 1. Важное различие между ними заключается в том, что тест 3 содержит квантификатор (\D*) и поэтому может использовать обратный откат, в то время как тест 1 не будет. Что происходит, так это то, что вы спросили: "Верно ли, что в начале $x, после 0 или более нецифр, у вас есть что-то, что не является 123?" Если бы обработчик шаблонов позволил \D* расшириться до "ABC", это привело бы к тому, что весь шаблон не сопоставился.
Поисковая система первоначально сопоставит \D* со "ABC". Затем она попытается сопоставить (?!123) с "123", что завершится неудачей. Но поскольку в регулярном выражении использовался квантификатор (\D*), поисковая система может вернуться назад и повторить попытку соответствия другим способом в надежде на соответствие всему регулярному выражению.
Шаблон действительно, действительно хочет преуспеть, поэтому он использует стандартный обратный откат и повторение, и позволяет \D* расшириться только до "AB" в этот раз. Теперь действительно есть что-то, что следует за "AB", что не является "123". Это "C123", что достаточно.
Мы можем справиться с этим, используя и утверждение, и отрицание. Мы скажем, что первая часть в $1 должна быть последует и цифрой, и чем-то, что не является "123". Помните, что утверждения с опережением — это выражения нулевой ширины — они только смотрят, но не потребляют никакой части строки в их совпадении. Поэтому переписывая это таким образом, получается то, чего вы ожидали; то есть, случай 5 завершится неудачей, а случай 6 — успехом:
print "5: got $1\n" if $x =~ /^(\D*)(?=\d)(?!123)/;
print "6: got $1\n" if $y =~ /^(\D*)(?=\d)(?!123)/;
6: got ABC Другими словами, два утверждения нулевой ширины, расположенные рядом, работают так, как будто они объединены оператором И, так же, как вы бы использовали любые встроенные утверждения: /^$/ совпадает только в том случае, если вы находитесь в начале строки И в конце строки одновременно. Более глубокая истина заключается в том, что смежность в регулярных выражениях всегда означает И, за исключением случаев, когда вы явно пишите ИЛИ, используя вертикальную черту. /ab/ означает сопоставить "a" И (затем) сопоставить "b", хотя попытки сопоставления выполняются в разных позициях, потому что "a" — это не утверждение нулевой ширины, а утверждение единичной ширины.
ПРЕДУПРЕЖДЕНИЕ: Особенно сложные регулярные выражения могут занимать экспоненциальное время для решения из-за огромного числа возможных способов использования обратного отката для поиска соответствия. Например, без внутренних оптимизаций, выполняемых движком регулярных выражений, это займёт очень много времени:
'aaaaaaaaaaaa' =~ /((a{0,5}){0,5})*[c]/ И если вы использовали "*" внутри групп вместо ограничения их до 0—5 совпадений, то это заняло бы вечность — или пока не закончилось бы пространство стека. Кроме того, эти внутренние оптимизации не всегда применимы. Например, если вы поместите {0,5} вместо "*" в внешнюю группу, никакая текущая оптимизация не применима, и совпадение займёт много времени.
Мощным инструментом для оптимизации таких монстров является так называемая "независимая группа", которая не использует обратный откат (см. "(?>pattern)"). Обратите также внимание, что утверждения с нулевой длиной с опережением/запаздыванием не будут использовать обратный откат для соответствия хвоста, поскольку они находятся в "логическом" контексте: учитывается только совпадение.
Для примера, где побочные эффекты утверждений с опережением могут повлиять на последующее соответствие, см. "(?>pattern)".
Скриптовые выполнимые блоки
Выполнение скрипта — это, по существу, последовательность символов, все из одного и того же шрифта Unicode (см. "Scripts" в perlunicode), например, латинского или греческого. В большинстве случаев одно слово никогда не будет написано несколькими шрифтами, если это не атака со сведением. Примечательный пример —
paypal.com Эти буквы могут быть все латинскими (как в приведённом выше примере), или они могут быть все кириллическими (кроме точки), или они могут быть смесью двух. В случае интернет-адреса .com будет латинским, а любые кириллические буквы сделают его смесью, а не последовательностью скриптов. Человек, нажимающий на такую ссылку, не будет перенаправлен на реальный веб-сайт Paypal, но злоумышленник создаст подделку, чтобы попытаться получить конфиденциальную информацию от этого человека.
Начиная с Perl 5.28, теперь легко обнаружить строки, которые не являются последовательностями скриптов. Просто заключите почти любой шаблон, например, один из этих:
(*script_run:pattern)
(*sr:pattern) После того, как шаблон успешно сопоставлен, к нему добавляется дополнительное условие: каждый символ в нём должен быть из одного и того же шрифта (см. исключения ниже). Если это не так, происходит обратный откат, пока не будет найдено что-то, что целиком принадлежит одному шрифту и соответствует, или пока все возможности не будут исчерпаны. Это может вызвать много обратных отката, но, как правило, только вредоносный ввод приведёт к этому, хотя замедление может привести к атаке типа "отказ в обслуживании". Если ваши потребности позволяют, лучше всего сделать шаблон атомным, чтобы сократить количество обратных отката. Это так вероятно то, что вы хотите, что вместо этого:
(*script_run:(?>pattern)) можно написать любой из этих:
(*atomic_script_run:pattern)
(*asr:pattern) (См. "(?>pattern)".)
В Тайване, Японии и Корее принято использовать смесь символов из собственных шрифтов и базового китайского языка. Perl следует механизмам безопасности Unicode UTS 39 (https://unicode.org/reports/tr39/), разрешая такие смеси. Например, японские шрифты катакана и хирагана обычно смешиваются вместе на практике, наряду с некоторыми китайскими символами, и поэтому Perl обрабатывает их как единую последовательность скриптов.
Правила сопоставления десятичных цифр немного строже. Многие шрифты имеют свои собственные наборы цифр, эквивалентные западным 0 и 9. Некоторые, например, арабские, имеют более одного набора. Для того, чтобы строка считалась последовательностью скриптов, все цифры в ней должны принадлежать одному набору из десяти, как определяется по первой цифре. Например,
qr/(*script_run: \d+ \b )/x гарантирует, что сопоставленные цифры будут из одного набора из десяти. Вы не получите похожую цифру из другого шрифта, которая имеет другое значение, чем то, что она, кажется, представляет.
В Unicode есть три псевдошрифта, которые обрабатываются особенно.
"Неизвестный" применяется к кодовым точкам, значение которых ещё предстоит определить. В настоящее время Perl будет сопоставлять как последовательность скриптов любую строку, состоящую из одного из этих кодовых точек. Но любая строка, более длинная, чем одна кодовая точка, содержащая одну из этих кодовых точек, не будет рассматриваться как последовательность скриптов.
"Унаследованный" применяется к символам, которые изменяют другой символ, например, к какому-либо типу акцента. Они считаются принадлежащими шрифту основного символа и поэтому никогда не приводят к тому, что последовательность скриптов не совпадает.
Другая — это "Общие". Она включает в себя в основном знаки препинания, эмодзи, символы, используемые в математике и музыке, ASCII-цифры 0—9, и полные формы этих цифр. Эти символы могут встречаться вместе в тексте во многих шрифтах мира. Они также не приводят к тому, что последовательность скриптов не совпадает. Но, как и в других шрифтах, все цифры в последовательности должны принадлежать одному набору из десяти.
Этот конструктор незахватывающий. Вы можете добавить скобки к шаблону для захвата, если это необходимо. Вам придётся сделать это, если вы планируете использовать "(*ACCEPT) (*ACCEPT:arg)" и не хотите, чтобы он пропускал проверку последовательности скриптов.
Свойство Script_Extensions, изменённое UTS 39 (https://unicode.org/reports/tr39/), используется в качестве основы для этой функции.
Подводя итог,
-
Все последовательности длиной 0 или 1 являются последовательностями скриптов.
-
Более длинная последовательность является последовательностью скриптов только тогда, когда выполняются все следующие условия:
-
Ни одна кодовая точка в последовательности не имеет свойства
Script_ExtensionUnknown.В настоящее время это означает, что все кодовые точки в последовательности были назначены Unicode в качестве символов, которые не являются частными для использования или кодовыми точками замещения.
-
Все символы в последовательности взяты из шрифта "Общие" и/или шрифта "Унаследованный" и/или одного другого шрифта.
Шрифт символа определяется свойством
Script_Extensionsс учётом изменений UTS 39 (https://unicode.org/reports/tr39/), как описано выше. -
Все десятичные цифры в последовательности взяты из одного блока из 10 последовательных цифр.
-
Специальные команды управления обратным отката
Эти специальные шаблоны, как правило, имеют вид (*VERB:arg). Если не указано иное, аргумент arg является необязательным; в некоторых случаях он является обязательным.
Любой шаблон, содержащий специальную команду управления обратным откатом, которая допускает аргумент, имеет специальное поведение: при выполнении он устанавливает переменные текущего пакета $REGERROR и $REGMARK. При этом применяются следующие правила:
При неудаче переменная $REGERROR будет установлена в значение arg шаблона команды, если команда была вовлечена в неудачу совпадения. Если часть arg шаблона была опущена, то $REGERROR будет установлено в имя последней команды (*MARK:NAME) шаблона, выполненной, или в TRUE, если таковой не было. Также переменная $REGMARK будет установлена в FALSE.
При успешном совпадении переменная $REGERROR будет установлена в FALSE, а переменная $REGMARK будет установлена в имя последней команды (*MARK:NAME) шаблона, выполненной. Дополнительные подробности см. в объяснении команды (*MARK:NAME) ниже.
ПРИМЕЧАНИЕ: $REGERROR и $REGMARK — это не магические переменные, как $1 и большинство других переменных, связанных с регулярными выражениями. Они не локальны для области видимости и не являются только для чтения, а вместо этого являются переменными пакета, похожими на $AUTOLOAD. Они устанавливаются в пакете, содержащем код, выполнявший регулярное выражение (а не тот, который его компилировал, если они отличаются). При необходимости вы можете использовать local, чтобы локализовать изменения в этих переменных в конкретной области видимости перед выполнением регулярного выражения.
Если шаблон не содержит специального глагола обратного поиска, позволяющего аргумент, то $REGERROR и $REGMARK вообще не затрагиваются.
- Глаголы
-
-
(*PRUNE)(*PRUNE:NAME) -
Этот шаблон нулевой ширины обрезает дерево обратного поиска в текущей точке при обратном поиске при неудаче. Рассмотрим шаблон
/A (*PRUNE) B/, где A и B — сложные шаблоны. До тех пор, пока не будет достигнут глагол(*PRUNE), A может осуществлять обратный поиск по необходимости для соответствия. Как только он достигнут, соответствие продолжается в B, который также может осуществлять обратный поиск по необходимости; однако, если B не соответствует, дальнейшего обратного поиска не произойдёт, и шаблон немедленно завершится неудачей в текущей начальной позиции.Следующий пример подсчитывает все возможные совпадающие строки в шаблоне (без фактического сопоставления каких-либо из них).
'aaab' =~ /a+b?(?{print "$&\n"; $count++})(*FAIL)/; print "Count=$count\n";что даёт:
aaab aaa aa a aab aa a ab a Count=9Если мы добавим
(*PRUNE)перед подсчётом, как показано ниже'aaab' =~ /a+b?(*PRUNE)(?{print "$&\n"; $count++})(*FAIL)/; print "Count=$count\n";мы предотвратим обратный поиск и найдём количество самой длинной совпадающей строки в каждой совпадающей начальной точке, как показано ниже:
aaab aab ab Count=3В шаблоне может быть использовано любое количество утверждений
(*PRUNE).См. также
"(?>pattern)"и позитивные квантификаторы для других способов управления обратным поиском. В некоторых случаях использование(*PRUNE)можно заменить на(?>pattern)без функциональных различий; однако,(*PRUNE)может быть использовано для обработки случаев, которые нельзя выразить с помощью одного(?>pattern). -
(*SKIP)(*SKIP:NAME) -
Этот шаблон нулевой ширины похож на
(*PRUNE), за исключением того, что при неудаче он также указывает, что любая текст, соответствующий до выполнения шаблона(*SKIP), не может быть частью любого соответствия этого шаблона. Это эффективно означает, что движок регулярных выражений "пропускает" вперёд до этой позиции при неудаче и пытается сопоставить снова (предполагая, что есть достаточно места для соответствия).Имя шаблона
(*SKIP:NAME)имеет особое значение. Если был встречен(*MARK:NAME), то именно эта позиция используется в качестве "точки пропуска". Если не был встречен(*MARK)с таким именем, то оператор(*SKIP)не оказывает никакого эффекта. При использовании без имени "точка пропуска" — это место, где была точка соответствия при выполнении шаблона(*SKIP).Сравните следующее с примерами в
(*PRUNE); обратите внимание, что строка вдвое длиннее:'aaabaaab' =~ /a+b?(*SKIP)(?{print "$&\n"; $count++})(*FAIL)/; print "Count=$count\n";выводит
aaab aaab Count=2После того, как 'aaab' в начале строки было сопоставлено, и был выполнен
(*SKIP), следующая начальная точка будет там, где курсор находился во время выполнения(*SKIP). -
(*MARK:NAME)(*:NAME) -
Этот шаблон нулевой ширины может использоваться для маркировки точки, достигнутой в строке, когда определённая часть шаблона была успешно сопоставлена. Эту метку можно присвоить имя. Позже шаблон
(*SKIP)пропустит вперёд до этой точки, если при обратном поиске произойдёт неудача. Разрешается любое количество шаблонов(*MARK), и часть NAME может быть дублирована.В дополнение к взаимодействию с шаблоном
(*SKIP),(*MARK:NAME)может использоваться для "мечения" ветви шаблона, так что после соответствия программа сможет определить, какие ветви шаблона участвовали в соответствие.Когда соответствие выполняется успешно, переменная
$REGMARKбудет установлена на имя последнего выполненного(*MARK:NAME), который участвовал в соответствие.Это можно использовать для определения того, какая ветвь шаблона была сопоставлена, не используя отдельные группы захвата для каждой ветви, что, в свою очередь, может привести к повышению производительности, так как Perl не может оптимизировать
/(?:(x)|(y)|(z))/так эффективно, как что-то вроде/(?:x(*MARK:x)|y(*MARK:y)|z(*MARK:z))/.Когда соответствие завершилось неудачей, и если другой глагол не был вовлечён в провал соответствия и не предоставил собственного имени для использования, переменная
$REGERRORбудет установлена на имя последнего выполненного(*MARK:NAME).См. "(*SKIP)" для получения более подробной информации.
В качестве сокращения
(*MARK:NAME)можно записать(*:NAME). -
(*THEN)(*THEN:NAME) -
Это аналогично оператору "группы среза"
::из Raku. Как и(*PRUNE), этот глагол всегда соответствует, а при обратном поиске при неудаче заставляет движок регулярных выражений попробовать следующую альтернативу во внутренней группе (захвата или иного), имеющей альтернативы. Две ветви(?(condition)yes-pattern|no-pattern)не считаются альтернативой с точки зрения(*THEN).Его название происходит из наблюдения, что этот оператор в сочетании с оператором альтернативы (
"|") может быть использован для создания того, что по сути является блоком if/then/else на основе шаблона:( COND (*THEN) FOO | COND2 (*THEN) BAR | COND3 (*THEN) BAZ )Обратите внимание, что если этот оператор используется и НЕ внутри альтернативы, он действует точно так же, как оператор
(*PRUNE)./ A (*PRUNE) B /эквивалентно
/ A (*THEN) B /но
/ ( A (*THEN) B | C ) /не эквивалентно
/ ( A (*PRUNE) B | C ) /так как после соответствия A, но неудачи на B, глагол
(*THEN)вернётся назад и попробует C; но глагол(*PRUNE)просто завершится неудачей. -
(*COMMIT)(*COMMIT:arg) -
Это раку-шаблон "commit"
<commit>или:::. Это шаблон нулевой ширины, аналогичный(*SKIP), за исключением того, что при обратном поиске при неудаче он приводит к немедленной неудаче соответствия. Не будет больше попыток найти соответствие, продвигая указатель начала. Например,'aaabaaab' =~ /a+b?(*COMMIT)(?{print "$&\n"; $count++})(*FAIL)/; print "Count=$count\n";выводит
aaab Count=1Другими словами, после входа
(*COMMIT), если шаблон не соответствует, движок регулярных выражений не будет пытаться продолжить сопоставление остальной части строки. -
(*FAIL)(*F)(*FAIL:arg) -
Этот шаблон не соответствует ничего и всегда завершается неудачей. Он может использоваться для принудительного возврата к поиску. Он эквивалентен
(?!), но легче читается. На самом деле,(?!)оптимизируется в(*FAIL)внутри. Вы можете указать аргумент, чтобы в случае, если соответствие завершилось неудачей из-за этого директивыFAIL, аргумент можно получить из$REGERROR.Скорее всего, он полезен только в сочетании с
(?{})или(??{}). -
(*ACCEPT)(*ACCEPT:arg) -
Этот шаблон не соответствует ничего и вызывает завершение успешного соответствия в той точке, в которой был встречен шаблон
(*ACCEPT), независимо от того, есть ли ещё что-то для сопоставления в строке. Когда внутри вложенного шаблона, например, рекурсии, или в подшаблоне, динамически сгенерированном через(??{}), только самый внутренний шаблон немедленно заканчивается.Если
(*ACCEPT)находится внутри групп захвата, то группы отмечаются как завершённые в точке, в которой был встречен(*ACCEPT). Например:'AB' =~ /(A (A|B(*ACCEPT)|C) D)(E)/x;будет соответствовать, и
$1будетAB, а$2будет"B",$3не будет установлено. Если было сопоставлено другое ветвление во вложенных скобках, например, в строке 'ACDE', то"D"и"E"тоже должны были быть сопоставлены.Вы можете указать аргумент, который будет доступен в переменной
$REGMARKпосле завершения соответствия.
-
Предупреждение о \1 вместо $1
Некоторые люди слишком привыкают к написанию вещей вроде:
$pattern =~ s/(\W)/\\\1/g; Это унаследовано (для \1 до \9) для правой части подстановки, чтобы не шокировать пользователей sed, но это плохая привычка. Это потому, что в PerlThink правая часть s/// — это строка с двойными кавычками. \1 в обычной строке с двойными кавычками означает управляющий символ A. Обычный Unix-смысл \1 ухищрен для s///. Однако, если вы привыкнете к этому, у вас возникнут проблемы, если вы затем добавите модификатор /e.
s/(\d+)/ \1 + 1 /eg; # causes warning under -w Или если вы попытаетесь сделать
s/(\d+)/\1000/; Вы не можете сделать это двусмысленным, сказав \{1}000, тогда как вы можете исправить это с помощью ${1}000. Операция интерполяции не должна смешиваться с операцией сопоставления обратной ссылки. Конечно, они означают две разные вещи слева от s///.
Повторные шаблоны, сопоставляющие подстроку нулевой длины
ПРЕДУПРЕЖДЕНИЕ: Впереди сложный материал (и проза). Этот раздел нуждается в переработке.
Регулярные выражения обеспечивают лаконичный и мощный язык программирования. Как и в случае с большинством других инструментов, мощность сочетается со способностью причинить вред.
Распространённое злоупотребление этой мощью исходит из способности создавать бесконечные циклы с помощью регулярных выражений, с чем-то таким же безобидным, как:
'foo' =~ m{ ( o? )* }x; o? соответствует в начале "foo", и поскольку позиция в строке не перемещается совпадением, o? будет соответствовать снова и снова из-за квантификатора "*". Ещё один распространённый способ создания аналогичного цикла — с модификатором циклирования /g:
@matches = ( 'foo' =~ m{ o? }xg ); или
print "match: <$&>\n" while 'foo' =~ m{ o? }xg; или цикл, подразумеваемый split().
Однако, большой опыт показал, что многие задачи программирования могут быть значительно упрощены с помощью повторных подвыражений, которые могут соответствовать подстрокам нулевой длины. Вот простой пример:
@chars = split //, $string; # // is not magic in split
($whitewashed = $string) =~ s/()/ /g; # parens avoid magic s// / Таким образом, Perl допускает такие конструкции, принудительно прерывая бесконечный цикл. Правила для этого отличаются для циклов нижнего уровня, задаваемых жадными квантификаторами *+{}, и для циклов более высокого уровня, таких как модификатор /g или оператор split().
Циклы нижнего уровня прерываются (то есть цикл прерывается), когда Perl обнаруживает, что повторяющееся выражение соответствует подстроке нулевой длины. Таким образом
m{ (?: NON_ZERO_LENGTH | ZERO_LENGTH )* }x; эквивалентно
m{ (?: NON_ZERO_LENGTH )* (?: ZERO_LENGTH )? }x; Например, эта программа
#!perl -l
"aaaaab" =~ /
(?:
a # non-zero
| # or
(?{print "hello"}) # print hello whenever this
# branch is tried
(?=(b)) # zero-width assertion
)* # any number of times
/x;
print $&;
print $1; выводит
hello
aaaaa
b Обратите внимание, что «hello» выводится только один раз, так как когда Perl видит, что шестая итерация внешнего цикла (?:)* соответствует строке нулевой длины, он останавливает "*".
Циклы более высокого уровня сохраняют дополнительное состояние между итерациями: была ли последняя совпадение нулевой длины. Чтобы прервать цикл, следующему совпадению после совпадения нулевой длины запрещается иметь длину нуль. Это ограничение взаимодействует с возвратом назад (см. «Возврат назад»), поэтому выбирается второе по лучшим совпадение, если лучшее совпадение имеет нулевую длину.
Например:
$_ = 'bar';
s/\w??/<$&>/g; приводит к <><b><><a><><r><>. В каждой позиции строки лучшим совпадением, которое даёт нежадный ?? - это совпадение нулевой длины, а второе по лучшим совпадение - это то, что сопоставляется \w. Таким образом, совпадения нулевой длины чередуются с совпадениями длиной в один символ.
Аналогично, для повторяющегося m/()/g вторым по лучшим совпадением является совпадение в позиции на один шаг дальше в строке.
Дополнительное состояние совпадения с нулевой длиной ассоциируется с сопоставленной строкой и сбрасывается при каждом присваивании pos(). Совпадения нулевой длины в конце предыдущего совпадения игнорируются во время split.
Комбинирование фрагментов регулярных выражений
Каждый из элементарных фрагментов регулярных выражений, описанных ранее (таких как ab или \Z ), мог соответствовать не более чем одной подстроке в заданной позиции входной строки. Однако в типичном регулярном выражении эти элементарные фрагменты объединяются в более сложные шаблоны с помощью операторов объединения ST, S|T, S* и т. д. (в этих примерах "S" и "T" являются регулярными подвыражениями).
Такие комбинации могут включать альтернативы, что приводит к проблеме выбора: если мы сопоставим регулярное выражение a|ab со строкой "abc", будет ли это совпадение подстроки "a" или "ab"? Один из способов описания того, какая подстрока фактически сопоставляется, - это понятие возврата назад (см. «Возврат назад»). Однако это описание слишком низкого уровня и заставляет вас думать в терминах конкретной реализации.
Другое описание начинается с понятий «лучше»/«хуже». Все подстроки, которые могут быть сопоставлены данным регулярным выражением, могут быть отсортированы от «лучшего» совпадения до «худшего» совпадения, и выбирается «лучшее» совпадение. Это заменяет вопрос «что выбирается?» вопросом «какие совпадения лучше, а какие хуже?».
Опять же, для элементарных фрагментов такого вопроса нет, так как в данной позиции возможно не более одного совпадения. В этом разделе описывается понятие лучше/хуже для операторов объединения. В описании ниже "S" и "T" являются регулярными подвыражениями.
ST-
Рассмотрим два возможных совпадения,
ABиA'B',"A"иA'являются подстроками, которые могут быть сопоставлены с"S","B"иB'являются подстроками, которые могут быть сопоставлены с"T".Если
"A"является лучшим совпадением для"S"чемA', тоABявляется лучшим совпадением чемA'B'.Если
"A"иA'совпадают:ABявляется лучшим совпадением чемAB'если"B"является лучшим совпадением для"T"чемB'. -
S|T -
Когда
"S"может совпадать, это является лучшим совпадением, чем когда может совпадать только"T".Порядок двух совпадений для
"S"такой же, как для"S". Аналогично для двух совпадений для"T". -
S{REPEAT_COUNT} -
Совпадает как
SSS...S(повторяется столько раз, сколько необходимо). -
S{min,max} -
Совпадает как
S{max}|S{max-1}|...|S{min+1}|S{min}. -
S{min,max}? -
Совпадает как
S{min}|S{min+1}|...|S{max-1}|S{max}. -
S?,S*,S+ -
Так же, как
S{0,1},S{0,BIG_NUMBER},S{1,BIG_NUMBER}соответственно. -
S??,S*?,S+? -
Так же, как
S{0,1}?,S{0,BIG_NUMBER}?,S{1,BIG_NUMBER}?соответственно. -
(?>S) -
Совпадает с лучшим совпадением для
"S"и только с ним. -
(?=S),(?<=S) -
Рассматривается только лучшее совпадение для
"S". (Это важно только если"S"имеет группирующие скобки и где-то в целом регулярном выражении используются обратные ссылки.) -
(?!S),(?<!S) -
Для этого оператора группирования нет необходимости описывать порядок, так как важен только вопрос о том, может ли
"S"совпадать или нет. -
(??{ EXPR }),(?PARNO) -
Порядок такой же, как для регулярного выражения, которое является результатом EXPR, или шаблона, содержащегося в группе захвата PARNO.
-
(?(condition)yes-pattern|no-pattern) -
Напомним, что выбор, какой из yes-pattern или no-pattern фактически совпадает, уже определен. Порядок совпадений такой же, как для выбранного подвыражения.
Вышеупомянутые рецепты описывают порядок совпадений в заданной позиции. Требуется еще одно правило, чтобы понять, как определяется совпадение для всего регулярного выражения: совпадение в более ранней позиции всегда лучше, чем совпадение в более поздней позиции.
Создание пользовательских движков регулярных выражений
Начиная с Perl 5.10.0, можно создавать пользовательские движки регулярных выражений. Это не для слабонервных, так как они должны подключаться на уровне C. Подробнее см. perlreapi.
В качестве альтернативы перегруженные константы (см. overload) предоставляют простой способ расширения функциональности движка регулярных выражений, путем подстановки одного шаблона другим.
Предположим, что мы хотим включить новую последовательность экранирования RE \Y| , которая соответствует границе между символами пробела и не-пробела. Обратите внимание, что (?=\S)(?<!\S)|(?!\S)(?<=\S) соответствует именно этим позициям, поэтому мы хотим иметь каждый \Y| на месте более сложного варианта. Мы можем создать модуль customre для этого:
package customre;
use overload;
sub import {
shift;
die "No argument to customre::import allowed" if @_;
overload::constant 'qr' => \&convert;
}
sub invalid { die "/$_[0]/: invalid escape '\\$_[1]'"}
# We must also take care of not escaping the legitimate \\Y|
# sequence, hence the presence of '\\' in the conversion rules.
my %rules = ( '\\' => '\\\\',
'Y|' => qr/(?=\S)(?<!\S)|(?!\S)(?<=\S)/ );
sub convert {
my $re = shift;
$re =~ s{
\\ ( \\ | Y . )
}
{ $rules{$1} or invalid($re,$1) }sgex;
return $re;
} Теперь use customre включает новую последовательность экранирования в константных регулярных выражениях, то есть, без каких-либо интерполяций переменных во время выполнения. Как документировано в overload, эта конвертация будет работать только над буквальными частями регулярных выражений. Для \Y|$re\Y| переменная часть этого регулярного выражения должна быть преобразована явно (но только в том случае, если специальное значение \Y| должно быть включено внутри $re):
use customre;
$re = <>;
chomp $re;
$re = customre::convert $re;
/\Y|$re\Y|/; Частота выполнения встроенного кода
Точные правила о том, как часто выполняются (?{}) и (??{}) в шаблоне, не определены, и это ещё более верно для (*{}). В случае успешного совпадения можно предположить, что они будут работать в режиме «по умолчанию» и выполняться слева направо соответствующее количество раз на пути принятия шаблона, как и любой другой мета-шаблон. То, как не-приемлемые пути и неудачи совпадений влияют на количество раз, когда выполняется шаблон, не определено явно и может варьироваться в зависимости от применяемых оптимизаций шаблона и, вероятно, будет меняться от версии к версии.
Например, в
"aaabcdeeeee"=~/a(?{print "a"})b(?{print "b"})cde/; точное количество раз, когда «a» или «b» выводятся, не определено для неудач, но можно предположить, что они будут выводиться по крайней мере один раз во время успешного совпадения, кроме того, можно предположить, что если выводится «b», то ему будет предшествовать по крайней мере одно «a».
В случае разветвленных конструкций, как в следующем:
/a(b|(?{ print "a" }))c(?{ print "c" })/; можно предположить, что вход «ac» выведет «ac», а «abc» выведет только «c».
Когда встроенный код квантифицирован, успешные совпадения вызовут код один раз для каждой сопоставленной итерации квантификатора. Например:
"good" =~ /g(?:o(?{print "o"}))*d/; выведет «o» дважды.
По историческим и соображениям согласованности использование обычных блоков кода в любом месте шаблона отключит определенные оптимизации. Начиная с версии 5.37.7, вы можете использовать «оптимистичный» блок кода, (*{ ... }) как замену для (?{ ... }), если вы не хотите отключать эти оптимизации. Это может привести к тому, что блок кода будет вызываться реже, чем это могло бы быть, если бы они не были оптимистичными.
Поддержка PCRE/Python
Начиная с Perl 5.10.0, Perl поддерживает несколько расширений синтаксиса регулярных выражений, специфичных для Python/PCRE. Хотя программистам Perl рекомендуется использовать специфичный для Perl синтаксис, следующие варианты также принимаются:
-
(?P<NAME>pattern) -
Определение именованной группы захвата. Эквивалентно
(?<NAME>pattern). -
(?P=NAME) -
Обратная ссылка на именованную группу захвата. Эквивалентно
\g{NAME}. -
(?P>NAME) -
Вызов подпрограммы к именованной группе захвата. Эквивалентно
(?&NAME).
ОШИБКИ
Существует ряд проблем, связанных с сопоставлением без учёта регистра в правилах Юникода. См. "i" в разделе "Модификаторы" выше.
Этот документ колеблется от трудно понимаемого до совершенно и совершенно непрозрачного. Бродящая проза, изобилующая жаргоном, трудно уловим в нескольких местах.
Этот документ нуждается в переработке, которая разделяет учебный контент от справочного контента.
См. также
Синтаксис шаблонов, используемых в Perl для сопоставления шаблонов, эволюционировал от шаблонов, предоставленных в системах регулярных выражений Bell Labs Research Unix 8-й версии (версия 8). (Код фактически происходит (косвенно) от свободно распространяемой повторной реализации Henry Spencer этих программ V8.)
"Операторы цитирования регулярных выражений" в perlop.
"Подробности синтаксического анализа цитированных конструкций" в perlop.
Mastering Regular Expressions Джеффри Фридла, издательство O'Reilly and Associates.
© 1993–2023 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.38.0/perlre