Почему группа "non-capturing" регулярного выражения не работает - PullRequest
41 голосов
/ 24 апреля 2010

В моем фрагменте ниже группа без захвата "(?:aaa)" должна игнорироваться в результате сопоставления, поэтому результат должен быть только "_bbb".

Тем не менее, я получаю "aaa_bbb" в результате сопоставления; только когда я указываю группу (2), она показывает "_bbb".

>>> import re
>>> s = "aaa_bbb"
>>> print(re.match(r"(?:aaa)(_bbb)", s).group())

aaa_bbb

Ответы [ 6 ]

79 голосов
/ 24 апреля 2010

Я думаю, что вы неправильно понимаете концепцию "группы без захвата". Текст, сопоставленный группой без захвата, по-прежнему становится частью общего соответствия регулярному выражению.

И регулярное выражение (?:aaa)(_bbb), и регулярное выражение (aaa)(_bbb) возвращают aaa_bbb в качестве общего совпадения. Разница в том, что первое регулярное выражение имеет одну группу захвата, которая возвращает _bbb в качестве своего совпадения, в то время как второе регулярное выражение имеет две группы захвата, которые возвращают aaa и _bbb в качестве их соответствующих совпадений. В вашем коде Python, чтобы получить _bbb, вам нужно использовать group(1) с первым регулярным выражением и group(2) со вторым регулярным выражением.

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

Если вы действительно хотите исключить aaa из общего соответствия регулярному выражению, тогда вам нужно использовать lookaround . В этом случае позитивный взгляд делает свое дело: (?<=aaa)_bbb. С этим регулярным выражением group() возвращает _bbb в Python. Группы захвата не нужны.

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

38 голосов
/ 24 апреля 2010

group() и group(0) вернут весь матч. Последующие группы являются фактическими группами захвата.

>>> print (re.match(r"(?:aaa)(_bbb)", string1).group(0))
aaa_bbb
>>> print (re.match(r"(?:aaa)(_bbb)", string1).group(1))
_bbb
>>> print (re.match(r"(?:aaa)(_bbb)", string1).group(2))
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
IndexError: no such group

Если вам нужно то же поведение, что и group():

" ".join(re.match(r"(?:aaa)(_bbb)", string1).groups())

3 голосов
/ 24 апреля 2010

TFM

class re.MatchObject

group([group1, ...])

Возвращает одну или несколько подгрупп совпадений. Если есть единственный аргумент, результат - единственная строка; если имеется несколько аргументов, результатом является кортеж с одним элементом на аргумент. Без аргументов group1 по умолчанию равен нулю (возвращается полное совпадение). Если аргумент groupN равен нулю, соответствующим возвращаемым значением является вся совпадающая строка.

1 голос
/ 24 апреля 2010

Попробуйте:

print(re.match(r"(?:aaa)(_bbb)", string1).group(1))

group() совпадает с group(0), а группа 0 присутствует всегда, и это полное совпадение RE .

0 голосов
/ 24 апреля 2010

Используйте метод groups на объекте match вместо группы. Возвращает список всех буферов захвата. Групповой метод без аргумента возвращает полное совпадение регулярного выражения.

0 голосов
/ 24 апреля 2010

Вы должны указать group(1), чтобы получить только часть, захваченную скобкой (_bbb в данном случае).

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...