在Python中提取嵌套正则表达式的所有匹配项

1 投票
3 回答
987 浏览
提问于 2025-04-15 15:26

我正在尝试解析一个符合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)并不了解,学习这些可能对我有帮助。

撰写回答