我有一个幼稚的“解析器”,它只做以下事情: [x.split('=') for x in mystring.split(',')]
[x.split('=') for x in mystring.split(',')]
但是mystring可以像 'foo=bar,breakfast=spam,eggs'
'foo=bar,breakfast=spam,eggs'
显然, 天真的拆分器不会这样做。为此,我仅限于 python 2.6标准库 , 因此无法使用pyparsing。
预期输出为 [('foo', 'bar'), ('breakfast', 'spam,eggs')]
[('foo', 'bar'), ('breakfast', 'spam,eggs')]
我正在尝试使用正则表达式执行此操作,但是面临以下问题:
我的第一次尝试 r'([a-z_]+)=(.+),?' 给了我 [('foo', 'bar,breakfast=spam,eggs')]
r'([a-z_]+)=(.+),?'
[('foo', 'bar,breakfast=spam,eggs')]
显然, 使.+非贪婪不解决问题。
.+
因此, 我猜测我必须以某种方式使最后一个逗号(或$)成为必需。 这样做实际上是行不通的, r'([a-z_]+)=(.+?)(?:,|$)' 因为省略了逗号后面包含一个值的内容, 例如[('foo', 'bar'), ('breakfast', 'spam')]
$
r'([a-z_]+)=(.+?)(?:,|$)'
[('foo', 'bar'), ('breakfast', 'spam')]
我认为我必须使用某种look-behind(?)操作。 问题 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
编辑2:
只是为了满足我的好奇心,使用 纯正 则表达式实际上有可能吗?即,这样re.findall()将返回2元组的列表?
re.findall()
仅出于比较目的,这是一个正则表达式似乎也可以解决该问题:
([^=]+) # key = # equals is how we tokenise the original string ([^=]+) # value (?:,|$) # value terminator, either comma or end of string
这里的技巧是限制您在第二组中捕获的内容。.+吞下=符号,这是我们可以用来区分键和值的字符。完整的正则表达式不依赖任何回溯(因此,如果需要,它应该与re2之类的东西兼容),并且可以在abarnert的示例中使用。
=
用法如下:
re.findall(r'([^=]+)=([^=]+)(?:,|$)', 'foo=bar,breakfast=spam,eggs,blt=bacon,lettuce,tomato,spam=spam')
哪个返回:
[('foo', 'bar'), ('breakfast', 'spam,eggs'), ('blt', 'bacon,lettuce,tomato'), ('spam', 'spam')]