Почему минимальное (не жадное) совпадение зависит от конца строкового символа '$'?

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

вопрос в том, почему наличие " $ " в регулярном выражении влияет на жадность выражения:

вот простой пример:

>>> import re
>>> str = "baaaaaaaa"
>>> m = re.search(r"a+$", str)
>>> m.group()
'aaaaaaaa'
>>> m = re.search(r"a+?$", str)
>>> m.group()
'aaaaaaaa'

в "?- похоже, ничего не делает. Обратите внимание, когда " $ " удаляется, однако, затем "? уважается:

>>> m = re.search(r"a+?", str)
>>> m.group()
'a'

изменить: Другими словами, " a+?$ "соответствует всем a вместо того, чтобы просто последний, это не то, что я ожидал. Вот описание regex"+?"из python docs: - Добавляя?"после того, как квалификатор заставляет его выполнять матч не жадным или минимальным способом; как можно меньше символов будет сопоставлено."

это, похоже, не так в этом примере: строка "a" соответствует регулярному выражению "a+?$ ", так почему же не совпадает с тем же регулярным выражением в строке "baaaaaaa" только один a (самый правый один)?

6 ответов


матчи "заказной" по "слева, потом длинная"; однако" самый длинный " - это термин, используемый до того, как не-жадный был разрешен, и вместо этого означает что-то вроде "предпочтительного количества повторений для каждого атома". Быть оставленным-самое более важно чем количество повторений. Таким образом,"+?$ "не будет соответствовать последнему A в "baaaaa", потому что соответствие в первом A начинается раньше в строке.

(ответ изменен после уточнения OP в комментариях. Видеть история предыдущего текста.)


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

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

EDIT:

Подробнее... В этом дело:

re.search(r"a+?$", "baaaaaaaa")

regex engine будет игнорировать все до первого "а", потому что это как re.search строительство. Он будет соответствовать первому a, и "хотел бы" вернуть матч, за исключением того, что он еще не соответствует шаблону, потому что он должен достичь соответствия для $. Так что он просто продолжает есть aпо одному за раз и проверка на $. Если бы он был жадным, он бы не проверял $ после каждого a, но только после того, как он больше не мог соответствовать as.

но в этом случае:

re.search(r"a+?", "baaaaaaaa")

regex engine проверит, имеет ли он полное совпадение после еды первого матча (потому что он не жадный) и успеха потому что нет $ в этом случае.


в присутствии $ в регулярном выражении не влияет на жадность выражения. Это просто добавляет еще одно условие, которое должно быть выполнено для общего успеха матча.

и a+ и a+? требуются, чтобы потреблять первый a они находят. Если это a следует больше a ' s,a+ идет вперед и потребляет их тоже, в то время как a+? довольствуется только одной. Если бы в регулярном выражении было что-то еще, a+ будет будьте готовы согласиться на меньшее aи a+? потребляет больше, если это то, что требуется для достижения соответствия.

С a+$ и a+?$, вы добавили еще одно условие: матч по крайней мере один a следовал по конец строки. a+ по-прежнему потребляет все aсначала, затем он передает якорь ($). Это удается с первой попытки, так что a+ не требуется, чтобы вернуть любой из его as.

С другой стороны, a+? первоначально потребляет только один a перед передачей $. Это не удается, поэтому управление возвращается в a+?, который потребляет другой a и снова руки. И так продолжается до тех пор, пока a+? потребляет последнего a и $ наконец-то удается. Так что да, a+?$ соответствует тому же числу aкак a+$, но делает это неохотно, а не жадно.

а на левой-длинный правило было упомянуто в другом месте, что никогда не применялось к Perl-производным вкусам регулярных выражений, таким как Python. Даже без неохотных кванторов они всегда могли вернуть менее чем максимальный матч благодаря заказал чере. Я думаю, у Яна есть правильная идея: Perl-производные (или regex-направленные) ароматы должны называться готовностью, не жадный.

я считаю, что самое левое-самое длинное правило применяется только к регексам POSIX NFA, которые используют двигатели NFA под капотом, но требуется вернуть те же результаты, что и регулярное выражение DFA (текстовое).


ответ на оригинальный вопрос:

почему первый поиск() продолжительность множественные " / " s вместо принимать короткий матч?

не-жадный subpattern примет самое короткое совпадение в соответствии со всей картины успеха. В вашем примере, последний шаблон $, поэтому предыдущие должны растянуться до конца строки.

ответ на пересмотренный вопрос:

не-жадный subpattern примет самое короткое совпадение в соответствии со всей картины успеха.

другой способ взглянуть на это: не-жадный subpattern изначально будет соответствовать кратчайшему возможному совпадению. Однако, если это приводит к сбою всего шаблона, он будет повторен с дополнительным символом. Этот процесс продолжается до тех пор, пока не произойдет сбой подшаблона (что приведет к сбою всего шаблона) или не будет совпадать весь шаблон.


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

>>> import re
>>> string = "baaa"
>>> 
>>> # Here you're searching for one or more `a`s until the end of the line.
>>> pattern = re.search(r"a+$", string)
>>> pattern.group()
'aaa'
>>> 
>>> # This means the same thing as above, since the presence of the `$`
>>> # cancels out any meaning that the `?` might have.
>>> pattern = re.search(r"a+?$", string)
>>> pattern.group()
'aaa'
>>> 
>>> # Here you remove the `$`, so it matches the least amount of `a` it can.
>>> pattern = re.search(r"a+?", string)
>>> pattern.group()
'a'

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

>>> # This is close to the example pattern with `a+?$` and therefore `a+$`.
>>> # It matches `a`s until the end of the line. Again the `?` can't do anything.
>>> pattern = re.search(r"(a+?)$", string)
>>> pattern.group(1)
'aaa'
>>>
>>> # In order to get the `?` to work, you need something else in your pattern
>>> # and outside your group that can be matched that will allow the selection
>>> # of `a`s to be lazy. # In this case, the `.*` is greedy and will gobble up
>>> # everything that the lazy `a+?` doesn't want to.
>>> pattern = re.search(r"(a+?).*$", string)
>>> pattern.group(1)
'a'

Edit: удален текст, связанный со старыми версиями вопроса.


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

>>> import os
>>> p = "/we/shant/see/this/butshouldseethis"
>>> os.path.basename(p)
butshouldseethis