我正在尝试匹配括号括起来的所有字符串。例如,对于以下字符串:
((5.85B8.5V + ?; 1.79") + (6.78A0 + ?; .97"); 4.760")
我希望匹配以下所有内容:
我从来没有真正掌握正则表达式,所以我遇到了麻烦。我现在拥有的是:
pattern = '\((.*?)\)'
m = re.match(pattern, string)
print m.group()
'((5.85B8.5V + ?; 1.79")'
这有点接近,但得到两种类型的第一个括号,而不是开括号和右括号。有什么想法吗?
谢谢!
答案 0 :(得分:3)
正则表达式在解析嵌套结构方面不好,但是,有些方言提供了递归运算符?R
或?n
,可以帮助您解决这个问题。 Python的股票re
不支持它,但幸运的是,有regex
模块可以做到:
>>> import regex
>>> s = '((5.85B8.5V + ?; 1.79") + (6.78A0 + ?; .97"); 4.760")'
>>> regex.findall(r'(?=(\((?:[^()]|(?1))*\)))', s)
['((5.85B8.5V + ?; 1.79") + (6.78A0 + ?; .97"); 4.760")', '(5.85B8.5V + ?; 1.79")', '(6.78A0 + ?; .97")']
也就是说,正则表达式不是解析通用上下文无关语言(你的字符串显然属于它)的最佳选择。考虑使用真正的解析器,你可以使用pyParsing或类似的包构建,或者只是手工编写代码 - 这在这里相当简单:
def expressions(s):
stack = []
for n, c in enumerate(s):
if c == '(':
stack.append(n+1)
elif c == ')':
yield s[stack.pop():n]
for x in expressions(s):
print x
答案 1 :(得分:1)
您可以使用re.findall
,但对于您的内部分组,一次使用r'\(([^()]*)\)'
,一次使用(.*)
(以匹配整个字符串):
>>> import pprint
>>> l= re.findall(r'\(([^()]*)\)',s)+re.findall(r'\((.*)\)',s)
>>> pprint.pprint(l)
['5.85B8.5V + ?; 1.79"',
'6.78A0 + ?; .97"',
'(5.85B8.5V + ?; 1.79") + (6.78A0 + ?; .97"); 4.760"']
答案 2 :(得分:1)
使用lookarounds来进行重叠匹配。
>>> s = '((5.85B8.5V + ?; 1.79") + (6.78A0 + ?; .97"); 4.760")'
>>> re.findall(r'(?=\(([^()]*|.*)\))', s)
['(5.85B8.5V + ?; 1.79") + (6.78A0 + ?; .97"); 4.760"', '5.85B8.5V + ?; 1.79"', '6.78A0 + ?; .97"']
我们只能通过外观进行重叠匹配。如果没有外表,这是不可能做到的。所以把你的模式放在一个积极的先行断言中。
第一个 \(([^()]*|.*)\)
\(
与文字(
符号匹配。 ()
称为捕获组。 [^()]*
匹配任何字符,但不匹配(
或)
零次或多次或|
匹配任何字符0次或多次贪婪.*
直到最后\)
1}}符号。