Группа с положительным просмотром и группа без захвата: другое поведение

Я использую регулярные выражения Python (модуль re) в своем коде и заметил различное поведение в этих случаях:

re.findall(r'\s*(?:[a-z]\))?[^.)]+', 'a) xyz. b) abc.') # non-capturing group
# results in ['a) xyz', ' b) abc']

а также

re.findall(r'\s*(?<=[a-z]\))?[^.)]+', 'a) xyz. b) abc.') # lookbehind
# results in ['a', ' xyz', ' b', ' abc']

Мне нужно получить только ['xyz', 'abc']. Почему примеры ведут себя по-разному и как получить желаемый результат?


person aplavin    schedule 04.02.2013    source источник


Ответы (2)


Причина, по которой a и b включены во второй случай, заключается в том, что (?<=[a-z]\)) сначала найдет a), а поскольку поиск не использует никаких символов, вы вернетесь в начало строки. Теперь [^.)]+ соответствует a

Теперь вы находитесь на ). Поскольку вы сделали (?<=[a-z]\)) необязательных [^.)]+ совпадений xyz

То же самое повторяется с b) abc

удалите ? из второго случая, и вы получите ожидаемый результат, т.е. ['xyz', 'abc']

person Anirudha    schedule 04.02.2013
comment
Незахватывающая группа в первом случае тоже необязательна (если в тексте нет a), то соответствует весь текст). - person aplavin; 04.02.2013
comment
@chersanya, вот почему я сказал второй случай, а не первый... между ними есть разница - person Anirudha; 04.02.2013
comment
@chersanya также проверяет поиск по указанному шаблону, но не ест никаких символов ... отсюда и результат - person Anirudha; 04.02.2013
comment
О, я понял) Настоящая проблема в том, что обходы ничего не потребляют, поэтому findall также находит a в a). - person aplavin; 04.02.2013
comment
Не могли бы вы добавить причину в свой ответ? - person aplavin; 04.02.2013
comment
@chersanya: Ничего не потреблять - плохое объяснение. Пропущенный текст можно считать использованным. Причина, по которой ваше исходное регулярное выражение терпит неудачу, явно связана с ?. - person nhahtdh; 04.02.2013
comment
@nhahtdh: ты уверен? Lookbehind не использует текст, поэтому вхождения a в a) и abc в abc не перекрываются. Если бы он потреблялся, не было бы никакой разницы с первым случаем, который я предоставил. - person aplavin; 04.02.2013
comment
@chersanya: Look-behind не использует текст, это правильно. Но поскольку вы делаете просмотр назад необязательным, регулярное выражение фактически \s*[^.)]+. Кажется, что опциональный просмотр назад поддерживается только в Python, и я не знаю, почему они это разрешают, хотя в этом нет смысла. - person nhahtdh; 04.02.2013
comment
@nhahtdh: но если бы он использовал текст, регулярное выражение с просмотром назад было бы (мой второй случай) эквивалентным первому случаю, который явно отличается от \s*[^.)]+? Или нет (почему)? - person aplavin; 04.02.2013
comment
@nhahtdh может быть необязательным.. это разрешено в .net.. но я согласен, что это действительно не имеет смысла - person Anirudha; 04.02.2013
comment
@chersanya: Я имел в виду, что из-за ? регулярное выражение сделано эквивалентным \s*[^.)]+, поскольку результат просмотра назад (будь то истина или ложь) не останавливает совпадение. - person nhahtdh; 04.02.2013
comment
@chersanya: Аргумент ничего не потреблять может сыграть роль в каком-то другом случае, но не в этом. - person nhahtdh; 04.02.2013

Регулярное выражение, которое вы ищете, это:

re.findall(r'(?<=[a-z]\) )[^) .]+', 'a) xyz. b) abc.')

Я считаю, что принятый в настоящее время ответ Анирудхи объясняет разницу между вашим использованием положительного взгляда назад и отсутствием захвата, однако предложение удалить ? после положительного взгляда назад фактически приводит к [' xyz', ' abc'] (обратите внимание на включенные пробелы).

Это связано с тем, что положительный просмотр назад не соответствует символу space, а также не включает space в сам основной класс соответствующих символов.

person TobalJackson    schedule 10.08.2017