regex python Поиск по вложенным группам
Есть следующий текст вида:
text = """
\tvoid hello_world (void) :
\t\treturn_type void
\t\twords_in_name 2
\t\t\tfirst, hello
\t\t\tsecond, world
\t\tparam_count 1
\tint main (char argv, char argc) :
\t\treturn_type int
\t\twords_in_name 1
\t\t\tfirst, main
\t\tparam_count 2
"""
Я пытаюсь разбить текст на подгруппы при помощи следующего регулярного выражения:
for function_match in re.finditer(r'\t{1}.+ :\n(\t{2}.+\n(\t{3}.+, .+\n)*){3}', text):
print(function_match.group(1))
Но из-за того, что я использую квантификаторы, при помощи метода function_match.group(1) могу получить лишь последнее соответствие шаблона. Есть ли способы получить список всех вхождений, чтобы обращаться к ним по индексу? Или, если перефразировать, есть ли возможность, используя метод .group(N), обратиться к паре 'b2, а не c3':
string='a1b2c3'
print(re.search(r'(?P<need_pair>\w\d)+', string).group('need_pair'))) #out: c3
p.s. Не хотелось бы отказываться от квантификаторов, так как нужно точное соответствие шаблону.
Ответы (1 шт):
В рамках стандартного re такое невозможно. Группа всегда будет хранить только последнее соответствие. Модуль regex может выдать всю "историю" соответствий группы, но иерархию вы также не получите (на обычном re то же самое делается тремя отдельными регекспами).
Но ничего же не мешает распарсить иерархично хоть теми же регулярными выражениями. Первый регексп берёт строку с одним табом (процедура) и остальные "подстроки" как "тело" этой процедуры. Второй регексп уже работает с "телом процедуры". И т.д.
import re
parsed = {}
for m1 in re.finditer(r'^\t{1}(?P<proc>[^\t].*?)\s+:\s*\n(?P<body>(^\t{2}[^\t].*?\n(^\t{3}[^\t].*?\n)*)+)', text, flags=re.M):
parsed[m1["proc"]] = {}
print(f'Procedure: {m1["proc"]}')
for m2 in re.finditer(r'^\t{2}(?P<prop_name>[^\t].*?)\s+(?P<prop_value>.+?)\n(?P<options>(^\t{3}[^\t].*?\n)*)', m1["body"], flags=re.M):
parsed[m1["proc"]][m2["prop_name"]] = {"value": m2["prop_value"], "options": {}}
print(f' Property `{m2["prop_name"]}` = `{m2["prop_value"]}`')
for m3 in re.finditer(r'^\t{3}(?P<name>[^\t].*?),\s+(?P<value>.+?)$', m2["options"], flags=re.M):
parsed[m1["proc"]][m2["prop_name"]]["options"][m3["name"]] = m3["value"]
print(f' Option `{m3["name"]}` : `{m3["value"]}`')
if not parsed[m1["proc"]][m2["prop_name"]]["options"]:
del parsed[m1["proc"]][m2["prop_name"]]["options"]
print("-"*40)
from pprint import pprint
pprint(parsed)
В результате имеем:
Procedure: void hello_world (void)
Property `return_type` = `void`
Property `words_in_name` = `2`
Option `first` : `hello`
Option `second` : `world`
Property `param_count` = `1`
Procedure: int main (char argv, char argc)
Property `return_type` = `int`
Property `words_in_name` = `1`
Option `first` : `main`
Property `param_count` = `2`
----------------------------------------
{'int main (char argv, char argc)': {'param_count': {'value': '2'},
'return_type': {'value': 'int'},
'words_in_name': {'options': {'first': 'main'},
'value': '1'}},
'void hello_world (void)': {'param_count': {'value': '1'},
'return_type': {'value': 'void'},
'words_in_name': {'options': {'first': 'hello',
'second': 'world'},
'value': '2'}}}
