Как это? сделать квантификатор ленивым в регулярном выражении
В последнее время я просматриваю регулярное выражение и полагаю, что оператор ?
делает команды *
, +
или ?
ленивыми. Мой вопрос: как это сделать? Это то, что *?
, например, является специальным оператором, или ?
влияет на *
? Другими словами, regex распознает *?
как один оператор сам по себе, или regex распознает *?
как два отдельных оператора *
и ?
? Если это так, что *?
распознается как два отдельных оператора, как ?
влияет на *
, чтобы сделать его ленивым. Если ?
означает, что *
является необязательным, не означает ли это, что *
вообще не существует. Если это так, то в выражении .*?
не будет ли регулярное выражение соответствовать отдельным буквам и всей строкой вместо более короткой строки? Пожалуйста, объясните, я отчаянно хочу понять. Большое спасибо.
Ответы
Ответ 1
Я думаю, что небольшая история облегчит понимание. Когда Ларри Стена хотела вырастить синтаксис регулярных выражений для поддержки новых функций, его варианты были сильно ограничены. Он не мог просто указывать (например), что %
теперь является метасимволом, который поддерживает новую функцию "XYZ". Это сломало бы миллионы существующих регулярных выражений, которые использовали %
для соответствия буквенному знаку процента.
Что он может сделать, это взять уже определенный метасимвол и использовать его таким образом, чтобы его оригинальная функция не имела смысла. Например, любое регулярное выражение, содержащее два квантора в строке, было бы недействительным, поэтому было бы безопасно сказать a ?
после того, как другой квантор теперь превратит его в неохотный квантификатор (гораздо лучшее имя, чем "ленивое" ИМО, не жадное тоже хорошо). Таким образом, ответ на ваш вопрос заключается в том, что ?
не изменяет *
, *?
- это единый объект: неохотный квантификатор. То же самое относится к +
в адвективных квантификаторах (*+
, {0,2}+
и т.д.).
Аналогичный процесс произошел с синтаксисом группы. Было бы бессмысленно иметь квантификатор после неоткрытой открывающей круглой скобки, поэтому было бы безопасно сказать, что (?
теперь знаменует начало специальной групповой конструкции. Но только знак вопроса будет поддерживать только одну новую функцию, поэтому для самого ?
, за которым следует следовать, должен следовать хотя бы один символ, чтобы указать, какая группа это ((?:...)
, (?<!...)
и т.д.). Опять же, (?:
представляет собой единый объект: открывающий разделитель группы, не являющейся захватом.
Я не знаю, почему он использовал знак вопроса оба раза. Я знаю Perl 6 Rules (воссоздание восходящего потока в Perl 5 regexes) покончил со всем этим дерьмом и использует бесконечно более разумный синтаксис.
Ответ 2
?
может означать много разных вещей в разных контекстах.
- После нормального токена регулярного выражения (символ, сокращенное обозначение, класс символов, группа...), это означает "сопоставить предыдущий элемент в 0-1 раза".
- После квантификатора, такого как
?
, *
, +
, {n,m}
, он принимает другое значение: "Сделать предыдущий квантор ленивым, а не жадным (если это значение по умолчанию, которое можно изменить, хотя, например, в PHP, модификатор /U
делает все кванторы леними по умолчанию, поэтому дополнительный ?
делает их жадными).
-
Сразу после открытия круглой скобки он отмечает начало специальной конструкции, например,
a) (?s)
: модификаторы режима ( "включить режим доты" )
b) (?:...)
: сделать группу не захватывающей
c) (?=...)
или (?!...)
: утверждение lookahead
d) (?<=...)
или (?<!...)
: утверждение lookbehind
e) (?>...)
: атомная группа
f) (?<foo>...)
: названная группа захвата
g) (?#comment)
: встроенные комментарии, игнорируемые движком regex
h) (?(?=if)then|else)
: условные обозначения
и другие. Не все конструкции доступны во всех вариантах регулярных выражений.
- В классе символов (
[?]
) он просто соответствует дословному ?
.
Ответ 3
Представьте, что у вас есть следующий текст:
BAAAAAAAAD
Возвращаются следующие регулярные выражения:
/B(A+)/ => 'BAAAAAAAA'
/B(A+?)/ => 'BA'
/B(A*)/ => 'BAAAAAAAA'
/B(A*?)/ => 'B'
Добавление "?" к операторам + и * делает их "ленивыми" - то есть они будут соответствовать абсолютному минимуму, требуемому для выражения, которое должно быть истинным. В то время как по умолчанию операторы * и + являются "жадными" и пытаются сопоставить AS MUCH AS POSSIBLE, чтобы выражение было истинным.
Помните + означает "один или несколько", поэтому минимум будет "один, если возможно, больше, если это абсолютно необходимо", тогда как максимум будет "все, если это возможно, если это абсолютно необходимо".
И * означает "ноль или больше", поэтому минимум будет "ничего, если это возможно, больше, если это абсолютно необходимо", тогда как максимум будет "все, если возможно, ноль, если это абсолютно необходимо".
Ответ 4
Это очень зависит от реализации, я думаю. Но поскольку каждый квантификатор, о котором я знаю, может быть изменен с помощью ?
, было бы разумно реализовать его таким образом.