Регулярное выражение Python: сопоставление скобок в скобках

Я пытался сопоставить следующую строку:

string = "TEMPLATES = ( ('index.html', 'home'), ('base.html', 'base'))"

Но, к сожалению, мое знание регулярных выражений очень ограничено, так как вы можете видеть, что есть две круглые скобки, которые нужно сопоставить, а также содержимое внутри второго Я попытался использовать re.match("\(w*\)", string), но это не сработало, любая помощь будет принята с благодарностью.

Ответы

Ответ 1

Попробуйте следующее:

import re
w = "TEMPLATES = ( ('index.html', 'home'), ('base.html', 'base'))"

# find outer parens
outer = re.compile("\((.+)\)")
m = outer.search(w)
inner_str = m.group(1)

# find inner pairs
innerre = re.compile("\('([^']+)', '([^']+)'\)")

results = innerre.findall(inner_str)
for x,y in results:
    print("%s <-> %s" % (x,y))

Вывод:

index.html <-> home
base.html <-> base

Объяснение:

outer соответствует первой группе скобок с помощью \( и \); по умолчанию search находит самое длинное совпадение, предоставляя нам самую внешнюю пару ( ). Матч m содержит именно то, что между этими внешними круглыми скобками; его содержимое соответствует бит .+ outer.

innerre соответствует точно одной из ваших пар ('a', 'b'), снова используя \( и \) для соответствия родительским содержимым в вашей входной строке и используя две группы внутри ' ', чтобы соответствовать строкам внутри эти одинарные кавычки.

Затем мы используем findall (а не search или match), чтобы получить все соответствия для innerre (а не только одного). На данный момент results - это список пар, о чем свидетельствует цикл печати.

Обновление: Чтобы соответствовать всему, вы можете попробовать что-то вроде этого:

rx = re.compile("^TEMPLATES = \(.+\)")
rx.match(w)

Ответ 2

Прежде всего, использование \( недостаточно для сопоставления скобок. Python обычно реагирует на некоторые escape-последовательности в своих строках, поэтому он интерпретирует \( как простой (. Вам нужно либо написать \\(, либо использовать необработанную строку, например. r'\(' или r"\(".

Во-вторых, когда вы используете re.match, вы привязываете поиск регулярных выражений к началу строки. Если вы хотите найти шаблон в любом месте строки, используйте re.search.

Как сказал Джозеф в своем ответе, не совсем ясно, что вы хотите найти. Например:

string = "TEMPLATES = ( ('index.html', 'home'), ('base.html', 'base'))"
print re.findall(r'\([^()]*\)', string)

будет печатать

["('index.html', 'home')", "('base.html', 'base')"]

EDIT:

Я исправлен, @phooji прав: экранирование в этом конкретном случае не имеет значения. Но re.match vs. re.search или re.findall по-прежнему важны.

Ответ 3

Если ваши строки выглядят как действительный код Python, вы можете это сделать:

import ast
var, s = [part.strip() for part in 
     "TEMPLATES = ( ('index.html', 'home'), ('base.html', 'base'))".split('=')]
result= ast.literal_eval(s)

Ответ 4

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

Я думаю, вам следует рассмотреть возможность разделения строки на запятые. Какова ваша конечная цель?

Ответ 5

Лучше всего использовать соответствующий модуль синтаксического анализа, например, пипарирование.