2016-09-20 3 views
4

Мне нужно найти все строки, соответствующие шаблону, за исключением двух заданных строк.Регулярное выражение, соответствующее всем, кроме строки

Например, найдите все группы букв, за исключением aa и bb. Начиная с этой строки:

-a-bc-aa-def-bb-ghij- 

Если вернуться:

('a', 'bc', 'def', 'ghij') 

Я попытался с this regular выражением, которое захватывает 4 струны. Я думал, что приближаюсь, но (1) он не работает на Python и (2) я не могу понять, как исключить несколько строк из поиска. (Да, я мог бы удалить их позже, но мое реальное регулярное выражение делает все за один выстрел, и я хотел бы включить в него этот последний шаг.)

Я сказал, что это не работает на Python, потому что я пробовал это, ожидая тот же результат, но вместо этого я получаю только первую группу:

>>> import re 
>>> re.search('-(\w.*?)(?=-)', '-a-bc-def-ghij-').groups() 
('a',) 

Я попытался с отрицательным прогностическим, но я не мог найти рабочее решение для этого случая.

+0

Вы хотите ['findall'] (https://docs.python.org/2/library/re.html#re.findall) -' поиск' должен только возвращать первое совпадение :) – cxw

ответ

6

Вы можете использовать отрицательный aheads вида.

Например,

>>> re.findall(r'-(?!aa|bb)([^-]+)', string) 
['a', 'bc', 'def', 'ghij'] 

  • - Матчи -

  • (?!aa|bb) отрицательного предпросмотра, проверяет, является ли - не следует aa или bb

  • ([^-]+) Матчи оны или более символов, кроме -


Редактировать

выше регулярное выражение не будет соответствовать тем, которые начинаются с aa или bb, например, как -aabc-. Для того, чтобы заботиться о том, что мы можем добавить - к lookaheads как,

>>> re.findall(r'-(?!aa-|bb-)([^-]+)', string) 
+0

Просто FYI: '' (?! Aa | bb) 'lookahead не разрешает те совпадения, которые * start * с' aa' или 'bb'. Итак, скажем, 'aacn' [не будет соответствовать] (https://regex101.com/r/jR5sH1/1). –

+0

@ WiktorStribiżew Действительная точка. Я добавил редактирование ответа. Спасибо за указание :) – nu11p01n73R

+0

Да, я просто думаю, что '-' в конце действительно требуется - просто судя по входной строке OP. Если в конце нет '-', ваше регулярное выражение вернет совпадение, мое не будет. Этот момент не ясен, но я думаю, что для него это дало. –

2

Чтобы найти все совпадения, вам нужно использовать отрицательный lookahead, чтобы ограничить более общий шаблон, и re.findall.

Использование

res = re.findall(r'-(?!(?:aa|bb)-)(\w+)(?=-)', s) 

или - если ваши значения между дефисом могут быть любым, но дефис, использовать отрицание класса символов [^-]:

res = re.findall(r'-(?!(?:aa|bb)-)([^-]+)(?=-)', s) 

Вот является regex demo.

Детали:

  • - - дефис
  • (?!(?:aa|bb)-) - если есть aa- или bb- после первого дефиса, ничего не должно быть возвращено
  • (\w+) - Группа 1 (это значение будет возвращен вызовом re.findall), захватывая 1 или более символов слова ИЛИ[^-]+ - 1 или более символов кроме -
  • (?=-) - после слова chars должно быть -. Здесь требуется просмотр, чтобы обеспечить совпадение совпадений (так как этот дефис будет отправной точкой для следующего совпадения).

Python demo:

import re 
p = re.compile(r'-(?!(?:aa|bb)-)([^-]+)(?=-)') 
s = "-a-bc-aa-def-bb-ghij-" 
print(p.findall(s)) # => ['a', 'bc', 'def', 'ghij'] 
+0

Я буду добавьте это замечание здесь тоже: я думаю, что последний взгляд требуется, потому что последнее совпадение имеет силу только в том случае, если за ним следует '-'. Это выводится из строки OP, поэтому не обязательно. –

0

Хотя регулярное выражение решение попросили, я бы сказал, что эта проблема может быть решена проще с более простыми функциями питона, а именно строки разделения и фильтрации:

input_list = "-a-bc-aa-def-bb-ghij-" 
exclude = set(["aa", "bb"]) 
result = [s for s in input_list.split('-')[1:-1] if s not in exclude] 

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

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