2014-11-03 3 views
0

Я пытаюсь использовать квантор ?, чтобы соответствовать шаблону, только если он существует, но я не могу заставить его работать так, как я хочу. В приведенном ниже примере я пытаюсь извлечь пару цифр после AZA и ZZZ, где ZZZ появляется все время, но AZA не является обязательным. Когда AZA отсутствует, я просто хочу, чтобы вернуть ('', [zzz-value]) пара (пустую строку вместо значения AZA):Необязательный шаблон регулярных выражений

Вход:

AZA:00zx--- 
ZZZ:32fd--- 
testxfiler 
gsdkfklsd 
fdsfsk 
AZA:06x--- 
ZZZ:50---- 
gsdkfklsd 
gsdkfklsd 
fdsfsk 
fdsfsk 
gsdkfklsd 
fdsfsk 
ZZZ:32zzz---- 
fdsfsk 
fdsfsk 
gsdkfklsd 
fdsfsk 
AZA:46---- 
ZZZ:53--- 

Желаемый результат:

[(00,32), (06, 50), ('',32), (46,53)] 

Моя попытка:

re.findall('(?:AZA:([0-9]*))?.*?ZZZ:([0-9]*)', text, re.DOTALL) 

Мой выход:

[('00', '32'), ('', '50'), ('', '32'), ('', '53') 

ответ

3
(?:AZA:(\d+).*?)?ZZZ:(\d+) 

См demo

import re 
p = re.compile(ur'(?:AZA:(\d+).*?)?ZZZ:(\d+)', re.DOTALL) 
test_str = u"AZA:00zx---\nZZZ:32fd---\ntestxfiler\ngsdkfklsd\nfdsfsk\nAZA:06x---\nZZZ:50----\ngsdkfklsd\ngsdkfklsd\nfdsfsk\nfdsfsk\ngsdkfklsd\nfdsfsk\nZZZ:32zzz----\nfdsfsk\nfdsfsk\ngsdkfklsd\nfdsfsk\nAZA:46----\nZZZ:53---" 

re.findall(p, test_str) 
+1

Спасибо, это сработало. Не могли бы вы объяснить мне кратко, почему это работает, а у меня нет? – confused00

+1

@ confused00 и т. Д. То же самое, что размещение '?' Отличается .Yur'. *? 'Перед' ZZZ' будет потреблять часть 'AZA' также, поскольку' AZA' является необязательным. Вот почему вы получаете '\ d +' 'ZZZ', а не' AZA'. Посмотрите http://regex101.com/r/bB8jY7/6 – vks

+0

Я вижу, спасибо – confused00

1

Вам не нужно добавить модификатор DOTALL,

>>> text = """AZA:00zx--- 
ZZZ:32fd--- 
testxfiler 
gsdkfklsd 
fdsfsk 
AZA:06x--- 
ZZZ:50---- 
gsdkfklsd 
gsdkfklsd 
fdsfsk 
fdsfsk 
gsdkfklsd 
fdsfsk 
ZZZ:32zzz---- 
fdsfsk 
fdsfsk 
gsdkfklsd 
fdsfsk 
AZA:46---- 
ZZZ:53---""" 
>>> re.findall(r'(?:AZA:([0-9]+)[\S\s]*?)?ZZZ:([0-9]+)', text) 
[('00', '32'), ('06', '50'), ('', '32'), ('46', '53')] 

DEMO

[\S\s]* будет соответствовать любому пространству или некосмическим персонаж с нуля или более раз.

Почему ваше регулярное выражение не работает?

(?:AZA:([0-9]*))?.*?ZZZ:([0-9]*) 

Мы все знаем, что в режиме DOTALL, точку в регулярном выражении будет соответствовать даже разрывам строк также. Таким образом, делая (?:AZA:([0-9]*))? как необязательный, следующее .*? будет соответствовать всем предыдущим символам, которые присутствуют до ZZZ:([0-9]*). Таким образом, включив следующее .*? в предыдущую необязательную группу, получим AZA:(\d+), чтобы соответствовать, если он представлен, и цифры, следующие за AZA:, будут сняты. Теперь он не сделает ненужного матча.

+1

Это решение предполагает, что если AZA существует, то он должен находиться на смежном линия. – nhahtdh

+0

отредактирован .......... –

+0

Это действительно так - они находятся на смежных линиях, если они оба появляются. Спасибо за ответ Авинаша. Я приму первый ответ, но я ценю помощь, приветствия. – confused00

1

Регулярное выражение вида

(?:AZA:(\d+)[^\n]*\n)?(?:ZZZ:)(\d+)[^\n]* будет полезно.

Например

>>>re.findall('(?:AZA:(\d+)[^\n]*\n)?(?:ZZZ:)(\d+)[^\n]*' ,x) 
[('00', '32'), ('06', '50'), ('', '32'), ('46', '53')] 
  • (?:AZA:(\d+)[^\n]*\n)? матчи :AZA: следуют цифры \d+ следуют ничем, кроме \n ([^\n]). Квантификатор в конце ? гарантирует, что вся группа является необязательной. Цифры захватываются в группе 1

  • (?:ZZZ:)(\d+)[^\n]* матчи :ZZZ: следуют цифры \d+ и ничего, кроме \n.Цифры захватили в группе 2

Что вы пропустили

re.findall('(?:AZA:([0-9]*))?.*?ZZZ:([0-9]*)', text, re.DOTALL)

весь (?:AZA:([0-9]*))?.*? должны были сделаны необязательными, как

(?:AZA:([0-9]*))?.*?)?

с последующим \n

изменив регулярное выражение как

re.findall('(?:AZA:([0-9]*).*?)?\nZZZ:([0-9]*)' ,x)

даст выход в

[('00', '32'), ('06', '50'), ('', '32'), ('46', '53')] 
+0

Спасибо за ответ и за объяснение, это тоже работает. Я согласен с первым ответом, который работал, но спасибо за вашу помощь – confused00

Смежные вопросы