Как я могу определить квантификатор для группы условий в регулярном выражении? - PullRequest
0 голосов
/ 17 января 2019

У меня есть эта строка:

"Za @Foo_Bar: @BAR_foo @FooBAR @BArfoo"

И шаблон регулярного выражения, подобный этому:

((Za\s)?@[A-Za-z0-9_]*)|(@[A-Za-z0-9_]*)

или

(Za\s)?@[A-Za-z0-9_]*

Я хочу вернуть этот список:

['Za @Foo_Bar','BAR_foo','FooBAR','BArfoo'] 

Но я получаю неожиданные результаты:

>>> import re
>>> import regex
>>> a = "Za @Foo_Bar: @BAR_foo @FooBAR @BArfoo"
>>> regex.fullmatch(u'((Za\s)?@[A-Za-z0-9_]*)|(@[A-Za-z0-9_]*)',a) is None
True
>>> re.findall(u'((Za\s)?@[A-Za-z0-9_]*)|(@[A-Za-z0-9_]*)',a)
[('Za @Foo_Bar', 'Za ', ''), ('@BAR_foo', '', ''), ('@FooBAR', '', ''), ('@BArfoo', '', '')]

Второй результат более убедителен, но содержит много ненужных значений:

>>> regex.findall(u'((Za\s)?@[A-Za-z0-9_]*)|(@[A-Za-z0-9_]*)',a)
[('Za @Foo_Bar', 'Za ', ''), ('@BAR_foo', '', ''), ('@FooBAR', '', ''), ('@BArfoo', '', '')]
>>> match  = re.search(u'((Za\s)?@[A-Za-z0-9_]*)|(@[A-Za-z0-9_]*)',a)
>>> match.groups()
('Za @Foo_Bar', 'Za ', None)

Почему fullmatch возвращает None? Как я могу получить чистый список?

Ответы [ 3 ]

0 голосов
/ 17 января 2019

regex.fullmatch() - неправильный метод для использования здесь, я не думаю, что вы поняли, для чего он полезен.

Из документации regex модуля :

fullmatch ведет себя как match, за исключением того, что оно должно соответствовать всей строке.

Ваш шаблон не соответствует всем входной строки. * Только если шаблон охватывает все , от первого до последнего символа, fullmatch() вернет совпадение.

Где re.match() соответствует только в начале строки, как если бы вы добавили \A в начало вашего паттерна, regex.fullmatch() соответствует, как если бы вы добавили \A в начало, и \Z до конца вашего шаблона.

Обратите внимание, что вам не нужна опция |(@[A-Za-z0-9_]*); этот шаблон полностью покрывается частью (Za\s)?@[A-Za-z0-9_]*, когда (Za\s)? не совпадает.

Чтобы получить чистый список, используйте re.findall(), но используйте (?:...) не захватывающую группу , чтобы покрыть необязательную часть, чтобы вы не получили отдельных строк в результате re.findall():

>>> import re
>>> a = "Za @Foo_Bar: @BAR_foo @FooBAR @BArfoo"
>>> re.findall(r'(?:Za\s)?@[A-Za-z0-9_]*', a)
['Za @Foo_Bar', '@BAR_foo', '@FooBAR', '@BArfoo']

Без групп захвата возвращается все совпадение.

0 голосов
/ 17 января 2019

Не использовать группы:

import re

s = "Za @Foo_Bar: @BAR_foo @FooBAR @BArfoo"
g = re.findall(r'(?:Za\s)@\w+|(?<=@)\w+', s)
print(g)

Выход:

['Za @Foo_Bar', 'BAR_foo', 'FooBAR', 'BArfoo']

Пояснение:

  (?:Za\s)  # non capture group
  @         # @
  \w+       # 1 or more word character
|           #
  (?<=@)    # lookbehind, make sure we have @ before
  \w+       # 1 or more word character
0 голосов
/ 17 января 2019

В качестве альтернативы вы можете использовать (?<!\AZa):? @ и разделить на необязательное двоеточие, за которым следует пробел и @, за исключением первого в строке:

import re
s = "Za @Foo_Bar: @BAR_foo @FooBAR @BArfoo"
print(re.split('(?<!\AZa):? @', s))

Результат

['Za @Foo_Bar', 'BAR_foo', 'FooBAR', 'BArfoo']

Regex demo | Python demo

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