正则表达式匹配以逗号分隔的key = value列表,其中value可以包含逗号

Kim*_*ais 8 python regex parsing python-2.6

我有一个天真的"解析器",只是做了类似的事情:
[x.split('=') for x in mystring.split(',')]

但是mystring可以是类似的东西
'foo=bar,breakfast=spam,eggs'

显然,
天真的分裂者不会这样做.我仅限于Python 2.6标准库,
因此例如pyparsing不能使用.

预期的产出是
[('foo', 'bar'), ('breakfast', 'spam,eggs')]

我正在尝试使用正则表达式,但面临以下问题:

我的第一次尝试
r'([a-z_]+)=(.+),?'
给了我
[('foo', 'bar,breakfast=spam,eggs')]

显然,
使.+非贪婪不解决问题.

所以,
我猜我必须以某种方式使最后一个逗号(或$)成为强制性的.
这样做并没有真正起作用,
r'([a-z_]+)=(.+?)(?:,|$)'
因为包含一个值的逗号后面的东西被省略了,
例如[('foo', 'bar'), ('breakfast', 'spam')]

我想我必须使用某种后视(?)操作.
问题
1. 我使用哪一个?或
2. 该怎么做/这个?

编辑:

根据daramarak在下面的回答,
我最后做的几乎与后来以稍微冗长的形式提出的abarnert相同;

vals = [x.rsplit(',', 1) for x in (data.split('='))]
ret = list()
while vals:
    value = vals.pop()[0]
    key = vals[-1].pop()
    ret.append((key, value))
    if len(vals[-1]) == 0:
        break
Run Code Online (Sandbox Code Playgroud)

编辑2:

只是为了满足我的好奇心,这真的可以用纯正则表达式吗?即这样re.findall()会返回2元组的列表?

ig0*_*774 10

仅仅为了比较的目的,这里的正则表达式似乎也解决了这个问题:

([^=]+)    # key
=          # equals is how we tokenise the original string
([^=]+)    # value
(?:,|$)    # value terminator, either comma or end of string
Run Code Online (Sandbox Code Playgroud)

这里的技巧是限制你在第二组中捕获的内容..+吞下=标志,这是我们可以用来区分键和值的字符.完整的正则表达式不依赖于任何反向跟踪(因此它应该与re2之类的东西兼容,如果这是可取的)并且可以使用abarnert的示例.

用法如下:

re.findall(r'([^=]+)=([^=]+)(?:,|$)', 'foo=bar,breakfast=spam,eggs,blt=bacon,lettuce,tomato,spam=spam')
Run Code Online (Sandbox Code Playgroud)

哪个回报:

[('foo', 'bar'), ('breakfast', 'spam,eggs'), ('blt', 'bacon,lettuce,tomato'), ('spam', 'spam')]
Run Code Online (Sandbox Code Playgroud)