在Python中提取嵌套正则表达式的所有匹配项
我正在尝试解析一个符合Python正则表达式的项目列表。
r'\A(("[\w\s]+"|\w+)\s+)*\Z'
也就是说,这个列表是用空格分开的,但在引号内的字符串可以包含空格。我想要得到这个列表中的项目(也就是被
r'("[\w\s]+"|\w+)'
匹配的项目)。所以,比如说
>>> parse('foo "bar baz" "bob" ')
['foo', '"bar baz"', '"bob"']
有没有什么好的方法可以用Python的re模块来做到这一点?
很多方法都不太管用。例如
>>> re.match(r'\A(("[\w\s]+"|\w+)\s+)*\Z', 'foo "bar baz" "bob" ').group(2)
'"bob"'
只返回了最后一个匹配的结果。另一方面,
>>> re.findall(r'("[\w\s]+"|\w+)', 'foo "bar baz" "bob" ')
['foo', '"bar baz"', '"bob"']
但它也接受一些格式不正确的表达式,比如
>>> re.findall(r'("[\w\s]+"|\w+)', 'foo "bar b-&&az" "bob" ')
['foo', 'bar', 'b', 'az', '" "', 'bob']
那么有没有办法使用原来的正则表达式,获取所有匹配到的第二组项目呢?类似于
>>> re.match_multigroup(r'\A(("[\w\s]+"|\w+)\s+)*\Z', 'foo "bar baz" "bob" ').group(2)
['foo', '"bar baz"', '"bob"']
>>> re.match_multigroup(r'("[\w\s]+"|\w+)', 'foo "bar b-&&az" "bob" ')
None
编辑:保持输出中的引号是很重要的,所以我不想要
>>> re.match_multigroup(r'\A(("[\w\s]+"|\w+)\s+)*\Z', 'foo "bar baz" "bob" ').group(2)
['foo', 'bar baz', 'bob']
因为那样我就不知道bob是否被引号包围了。
3 个回答
1
这里有一个解决方案,可以在不在引号里的空白处进行分割:
re.split('\s+(?=[^"]*(?:"[^"]*"[^"]*)*$)', target)
这个方法的前瞻检查只有在前面有偶数个引号时,才会成功匹配到刚刚找到的空白。如果你文本中的引号部分可能包含转义的引号,那么根据转义的方式,你可能需要一个更复杂的正则表达式。
2
我觉得正则表达式在这里不太合适。可以试试csv
模块:
>>> s = 'foo "bar baz" "bob" '
>>> for i in csv.reader([s], delimiter=' '):
print(i)
['foo', 'bar baz', 'bob', '']
1
好的,我决定把这个问题分成两个步骤来解决。
首先,我会检查这个表达式在语法上是否正确,其次我会把它拆分成一个个小部分:
def parse(expr):
if re.match(r'\A(("[\w\s]+"|\w+)\s+)*\Z', expr):
return re.findall(r'("[\w\s]+"|\w+)', expr)
所以:
>>> parse('foo "bar baz" "bob" ')
['foo', '"bar baz"', '"bob"']
>>> parse('foo "bar b-&&az" "bob" ')
>>> parse('foo "bar" ')
['foo', '"bar"']
>>> parse('"foo" bar ')
['"foo"', 'bar']
>>> parse('foo"bar baz" "bob" ')
>>> parse('&&')
我大约有90%的把握,这个方法对所有字符串都能正常工作,但我还是想知道有没有人能提供一个更通用的解决方案,因为我觉得这个方法有点笨拙。
感谢SilentGhost和Alan Moore的帮助。在此之前我对Python的csv模块和正则表达式的前瞻(lookaheads)并不了解,学习这些可能对我有帮助。