Python正则表达式:匹配括号中的括号

31
我一直在尝试匹配以下字符串:
string = "TEMPLATES = ( ('index.html', 'home'), ('base.html', 'base'))"

但很不幸,我对正则表达式的了解非常有限。你可以看到有两个需要匹配的括号,以及第二个括号内的内容。我尝试使用 re.match("\(w*\)", string),但它没有起作用。非常感谢任何帮助。

5个回答

38

试一下这个:

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(而不是searchmatch)来获取innerre的所有匹配项(而不仅仅是一个)。此时,results是一对列表,如打印循环所示。

更新:要匹配整个内容,可以尝试类似以下代码:

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

@paulo:我已经添加了一个正则表达式,可以匹配整个字符串。 - phooji
@akaRem:“许多人甚至不知道这些神秘的内置函数存在,如果他们被禁止使用它们作为变量名,他们会感到惊讶。从这里开始,这只是一个逐渐的过程。许多人编写带有参数名称str或len的函数或方法,或者使用类似于compile或format的名称。” Python的历史 - 3k-
@3k- 我不是母语人士,所以很难理解,你同意我的看法吗? - akaRem
@akaRem 我同意,不过这句话说的是 Python 故意设计成这样,以便人们可以覆盖内置函数。str 是一个内置函数,而不是关键字。关键字像 if,你不能覆盖 if - 3k-
@3k- 如果每个人都在任何地方多次覆盖所有内容怎么办?不,谢谢。 - akaRem
显示剩余3条评论

16

首先,仅仅使用\(是不能匹配括号的。在Python中,字符串中的某些转义序列会被解析,这就是为什么它将\(解释为简单的(。你需要写成\\(或使用原始字符串,例如r'\('r"\("

其次,当你使用re.match时,你是将正则表达式搜索定位在字符串的开头。如果你想在字符串的任何位置查找模式,请使用re.search

就像Joseph在他的答案中所说的那样,不清楚你想要查找什么。例如:

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

将会打印

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

编辑:

我改正了,@phooji是对的:在这种特定情况下转义是无关紧要的。但re.matchre.searchre.findall之间仍然很重要。


我想做的是匹配字符串 "TEMPLATES = ( ('index.html', 'home'), ('base.html', 'base'))" 并将其替换为另一个字符串,有没有一种方法可以匹配括号和 "TEMPLATES =" 部分?顺便说一下,谢谢你的解释。 - Paulo
实际上 re.match("\(hello\)", "(hello)") 可以正常工作,虽然我同意在正则表达式字面值中始终使用 r"..." 通常更容易些。 - phooji
@paulo:你想用那个匹配做什么,验证格式吗? - Vojislav Stojkovic
基本上,我正在打开一个 Django 设置文件,并匹配特定的字符串并替换其内容。 - Paulo

3

如果你的字符串看起来像是有效的Python代码,那么你可以这样做:

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

1

你的示例正在寻找紧随左括号后面的零个或多个字母w,然后是右括号。你可能想使用\w代替w,但在你的情况下这并不起作用,因为在左括号旁边有非单词字符。

我认为你应该考虑在逗号处拆分字符串。你的最终目标是什么?


0
如果您想验证括号在两层深度上是否平衡,您可以使用以下正则表达式:
import re;

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

pattern = re.compile(r"(?P<expression>\(([^()]*(?P<parenthesis>\()(?(parenthesis)[^()]*\)))*?[^()]*\))")

match = pattern.findall(string)

print(match[0][0])
print(match[1][0])
print(match[2][0])

这个正则表达式使用了条件语句 (?(parenthesis)[^()]*\))

演示:https://repl.it/@Konard/ParenthesesExample


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接