Python:如何用正则匹配嵌套括号?

26 投票
12 回答
53584 浏览
提问于 2025-04-16 14:33

我正在尝试匹配一个像数学表达式一样的字符串,这个字符串里面有嵌套的括号。

import re

p = re.compile('\(.+\)')
str = '(((1+0)+1)+1)'
print p.findall(s)

['(((1+0)+1)+1)']

我希望它能匹配所有被括号包围的表达式,比如 (1+0)、((1+0)+1) 等等...
我甚至不在乎它是否会匹配到一些不想要的,比如 (((1+0),这些我可以自己处理。

为什么它现在没有做到这一点,我该怎么做呢?

12 个回答

25

现在有一个新的正则表达式引擎模块正在准备中,目的是要替换掉Python里现有的那个。这个新模块带来了很多新功能,其中包括递归调用。

import regex

s = 'aaa(((1+0)+1)+1)bbb'

result = regex.search(r'''
(?<rec> #capturing group rec
 \( #open parenthesis
 (?: #non-capturing group
  [^()]++ #anyting but parenthesis one or more times without backtracking
  | #or
   (?&rec) #recursive substitute of group rec
 )*
 \) #close parenthesis
)
''',s,flags=regex.VERBOSE)


print(result.captures('rec'))

输出结果:

['(1+0)', '((1+0)+1)', '(((1+0)+1)+1)']

regex相关的bug:http://code.google.com/p/mrab-regex-hg/issues/detail?id=78

30

正如其他人提到的,正则表达式并不适合处理嵌套结构。我会用一个简单的例子来说明,使用的是pyparsing这个库:

import pyparsing # make sure you have this installed

thecontent = pyparsing.Word(pyparsing.alphanums) | '+' | '-'
parens     = pyparsing.nestedExpr( '(', ')', content=thecontent)

下面是一个使用示例:

>>> parens.parseString("((a + b) + c)")

输出结果:

(                          # all of str
 [
  (                        # ((a + b) + c)
   [
    (                      #  (a + b)
     ['a', '+', 'b'], {}   
    ),                     #  (a + b)      [closed]
    '+',
    'c'
   ], {}
  )                        # ((a + b) + c) [closed]
 ], {}  
)                          # all of str    [closed]

(这里的换行、缩进和注释都是手动处理的)

如果想要输出成嵌套列表的格式:

res = parens.parseString("((12 + 2) + 3)")
res.asList()

输出结果:

[[['12', '+', '2'], '+', '3']]
12

这个正则表达式会尽量匹配尽可能多的文本,所以它会把你整个字符串都用上。它不会在字符串的某些部分再寻找其他匹配的内容。这就是为什么你只得到一个结果的原因。

解决办法是不要使用正则表达式。如果你真的想解析数学表达式,应该使用专门的解析工具。如果你只是想提取括号里的内容,可以通过循环遍历字符,看到“(”就加一,看到“)”就减一,来计数。

撰写回答