Python Regex: захват перекрывающихся частей - PullRequest
2 голосов
/ 02 апреля 2020

Учитывая строку s = "<foo>abcaaa<bar>a<foo>cbacba<foo>c" Я пытаюсь написать регулярное выражение, которое будет извлекать части: угловые скобки с текстом внутри и окружающим текстом. Примерно так:

<foo>abcaaa
abcaaa<bar>a
a<foo>cbacba
cbacba<foo>c

Итак, ожидаемый результат должен выглядеть следующим образом:

["<foo>abcaaa", "abcaaa<bar>a", "a<foo>cbacba", "cbacba<foo>c"]

Я нашел этот вопрос Как найти перекрывающиеся совпадения с регулярным выражением? , которое принесло Я немного ближе к желаемому результату, но все равно мое регулярное выражение не работает.

regex = r"(?=([a-c]*)\<(\w+)\>([a-c]*))"

Есть идеи, как решить эту проблему?

Ответы [ 3 ]

2 голосов
/ 02 апреля 2020

Вы можете использовать этот код регулярного выражения в python:

>>> s = '<foo>abcaaa<bar>a<foo>cbacba<foo>c'
>>> reg = r'([^<>]*<[^>]*>)(?=([^<>]*))'
>>> print ( [''.join(i) for i in re.findall(reg, s)] )
['<foo>abcaaa', 'abcaaa<bar>a', 'a<foo>cbacba', 'cbacba<foo>c']

Демонстрация RegEx

Подробности RegEx:

  • ([^<>]*<[^>]*>): захватить группу № 1, чтобы найти 0 или более символов, которые не являются < и >, за которыми следует строка <...>.
  • (?=([^<>]*)): Ожидание, чтобы утверждать, что у нас 0 или более не <> символов перед текущей позицией. У нас есть группа захвата № 2 в этом виде.
2 голосов
/ 02 апреля 2020

Вы можете сопоставить перекрывающийся контент со стандартным синтаксисом регулярных выражений, используя группы захвата внутри косвенных утверждений, поскольку они могут совпадать с частями строки, не используя сопоставленную подстроку и, следовательно, исключая ее из дальнейших сопоставлений. В этом конкретном примере c мы сопоставляем либо начало строки, либо > в качестве якоря для утверждения предпросмотра, которое фиксирует наши реальные цели:

(?:\A|>)(?=([a-c]*<\w+>[a-c]*))

См. regex demo .

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

text = '<foo>abcaaa<bar>a<foo>cbacba<foo>c'
expr = r'(?:\A|>)(?=([a-c]*<\w+>[a-c]*))'
captures = re.findall(expr, text)
print(captures)

Вывод:

['<foo>abcaaa', 'abcaaa<bar>a', 'a<foo>cbacba', 'cbacba<foo>c']
2 голосов
/ 02 апреля 2020

Вам необходимо установить левую и правую границы на < или > символы или начало / конец строки.

Использовать

import re
text = "<foo>abcaaa<bar>a<foo>cbacba<foo>c"
print( re.findall(r'(?=(?<![^<>])([a-c]*<\w+>[a-c]*)(?![^<>]))', text) )
# => ['<foo>abcaaa', 'abcaaa<bar>a', 'a<foo>cbacba', 'cbacba<foo>c']

См. Python демо онлайн и демо регулярных выражений .

Детали шаблона

  • (?= - начало положительное ожидание включения перекрывающихся совпадений
    • (?<![^<>]) - начало строки, < или >
    • ([a-c]*<\w+>[a-c]*) - группа 1 (извлеченное значение): 0+ a, b или c символов, затем <, 1+ слов символов, > и снова 0+ a, b или c символов
    • (?![^<>]) - конец строки, < или > должен следовать сразу
  • ) - конец заглядывания.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...