Регулярное выражение Python, соответствующее нескольким строкам (re.DOTALL)

Я пытаюсь разобрать строку с несколькими строками.

Предположим, это:

text = '''
Section1
stuff belonging to section1
stuff belonging to section1
stuff belonging to section1
Section2
stuff belonging to section2
stuff belonging to section2
stuff belonging to section2
'''

Я хочу использовать метод finditer модуля re, чтобы получить словарь, например:

{'section': 'Section1', 'section_data': 'stuff belonging to section1\nstuff belonging to section1\nstuff belonging to section1\n'}
{'section': 'Section2', 'section_data': 'stuff belonging to section2\nstuff belonging to section2\nstuff belonging to section2\n'}

Я пробовал следующее:

import re
re_sections=re.compile(r"(?P<section>Section\d)\s*(?P<section_data>.+)", re.DOTALL)
sections_it = re_sections.finditer(text)

for m in sections_it:
    print m.groupdict() 

Но это приводит к:

{'section': 'Section1', 'section_data': 'stuff belonging to section1\nstuff belonging to    section1\nstuff belonging to section1\nSection2\nstuff belonging to section2\nstuff belonging to section2\nstuff belonging to section2\n'}

Таким образом, section_data также соответствует Section2.

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

re_sections=re.compile(r"(?P<section>Section\d)\s+(?P<section_data>^(?P=section))", re.DOTALL)

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

re_sections=re.compile(r"(?P<section>Section\d)\s+(?P<section_data>[a-z12\s]+)", re.DOTALL)

Большое спасибо!


person user2221323    schedule 11.04.2013    source источник
comment
Вы пытались сопоставить все вхождения r"(?:(?P<section>Section\d)\s*(?P<section_data>.+?))+" ?   -  person Aprillion    schedule 11.04.2013
comment
Да, это не работает. Вывод: {'section': 'Section1', 'section_data': 's'} {'section': 'Section2', 'section_data': 's'}   -  person user2221323    schedule 11.04.2013


Ответы (1)


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

re_sections=re.compile(r"(?P<section>Section\d)\s*(?P<section_data>.+?)(?=(?:Section\d|$))", re.DOTALL)

Обратите внимание, что для этого также требуется нежадный .+?, иначе он все равно будет соответствовать полностью до конца.

Демо:

>>> re_sections=re.compile(r"(?P<section>Section\d)\s*(?P<section_data>.+?)(?=(?:Section\d|$))", re.DOTALL)
>>> for m in re_sections.finditer(text): print m.groupdict()
... 
{'section': 'Section1', 'section_data': 'stuff belonging to section1\nstuff belonging to section1\nstuff belonging to section1\n'}
{'section': 'Section2', 'section_data': 'stuff belonging to section2\nstuff belonging to section2\nstuff belonging to section2'}
person Martijn Pieters    schedule 11.04.2013
comment
Уже попробовал, приводит к: {'section': 'Section1', 'section_data': 's'} {'section': 'Section2', 'section_data': 's'} - person user2221323; 11.04.2013
comment
@ user2221323: Да, тоже это заметил; нужен прогноз, обновил ответ. - person Martijn Pieters; 11.04.2013
comment
Большой! Это работает! Можно ли снова не упоминать Section\d в последней части ре (?=(?:Section\d|$)) и использовать ссылку типа (?=(?:(?P=section)|$ )). Это испытание приводит к тому же результату, что и в вопросе: / Я просмотрел утверждение «Положительный просмотр вперед». Насколько я понял, это удается, если повторное совпадение в текущем местоположении и все повторное повторение попытки в текущем местоположении? Но я не понимаю, зачем нужен |$? - person user2221323; 11.04.2013
comment
Нет, вы не можете повторно использовать совпадение section, потому что оно будет совпадать снова только в том случае, если оно имеет тот же номер раздела, то есть точно такой же литеральный текст. - person Martijn Pieters; 11.04.2013
comment
@user2221323: Упреждающий просмотр действует как якорь, текст перед ним совпадает, если позиция для упреждающего просмотра соответствует следующей части Section\d. Часть |$ необходима для соответствия последней записи в вашем тексте; либо есть раздел следующий, либо мы находимся в конце строки. - person Martijn Pieters; 11.04.2013