Нежадный квантификатор регулярного выражения дает жадный результат

У меня есть регулярное выражение .net, которое я тестирую с помощью Windows Powershell. Результат выглядит следующим образом:

> [System.Text.RegularExpressions.Regex]::Match("aaa aaa bbb", "aaa.*?bbb")


Groups   : {aaa aaa bbb}
Success  : True
Captures : {aaa aaa bbb}
Index    : 0
Length   : 11
Value    : aaa aaa bbb

Я ожидал, что использование квантификатора ? приведет к совпадению aaa bbb, так как второй группы достаточно для удовлетворения выражения. Является ли мое понимание нежадных квантификаторов ошибочным или я неправильно тестирую?

Примечание. Это явно не та же проблема, что и регулярное выражение, не жадное, является жадным


person Dominic Cronin    schedule 19.05.2013    source источник


Ответы (4)


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

Если вы действительно хотите обеспечить кратчайшее возможное совпадение, вам нужно сделать это явным. В данном случае это означает, что вместо .*? вам нужно подрегулярное выражение, которое соответствует всему, что не является ни aaa, ни bbb. Таким образом, результирующее регулярное выражение будет

aaa(?:(?!aaa|bbb).)*bbb
person Tim Pietzcker    schedule 19.05.2013
comment
Я просто сделал то, что должен был сделать в первую очередь, и проконсультировался с соответствующей главой Фридла. Это привело меня к aaa((?!aaa).)*bbb, что более или менее соответствует тому, что вы сказали, за исключением того, что в вашем ответе есть дополнительные подробности о том, что подвыражение не захватывается, а также тесты на bbb в отрицательном прогнозе. Хороший ответ. - person Dominic Cronin; 19.05.2013

Сравните результат для строки aaa aaa bbb bbb:

regex: aaa.*?bbb 
result: aaa aaa bbb

regex: aaa.*bbb
result: aaa aaa bbb bbb

Механизм регулярных выражений находит первое вхождение aaa, а затем пропускает все символы (.*?) до первого вхождения bbb, но для жадного оператора (.*) он находит больший результат и, следовательно, соответствует последнее появление bbb.

person j.holetzeck    schedule 19.05.2013
comment
Это самое ясное объяснение происходящего. +1 - person duozmo; 22.03.2014

Это не проблема жадности/лени. Проблема сводится к тому, что ваша строка анализируется слева направо. Когда первый aaa соответствует, механизм регулярных выражений добавляет символы один за другим, чтобы получить полный шаблон.

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

person Casimir et Hippolyte    schedule 19.05.2013

Ну, это очень просто, у нас есть следующая строка

ааа ааа ббб

Давайте посмотрим, что у нас есть это регулярное выражение aaa.*?bbb. Механизм регулярных выражений запустится с aaa

ааа ааа ббб

Механизм регулярных выражений теперь имеет .*?bbb. Это продолжится с space

ааа пробел ааа ббб

но у нас еще есть символы до bbb ? Таким образом, механизм регулярных выражений продолжит свой путь и сопоставит второй набор

ааа ааа пробел bbb

Наконец, механизм регулярных выражений будет соответствовать bbb:

ааа ааа bbb


Итак, давайте посмотрим, если мы хотим сопоставить только второй aaa, мы могли бы использовать следующее регулярное выражение:

(?<!^)aaa.*?bbb, это означает соответствие aaa тому, что не стоит в начале предложения.

Мы также можем использовать aaa(?= bbb).*?bbb, это означает соответствие aaa, за которым следует space bbb.

Посмотрите, как это работает 1 - 2.

Только что пришел в себя, а почему бы вам напрямую не использовать aaa bbb ?

person HamZa    schedule 19.05.2013