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

2024-04-20 00:19:55 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个天真的“解析器”,它只做了如下事情:
[x.split('=') for x in mystring.split(',')]

但是mystring可以是
'foo=bar,breakfast=spam,eggs'

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

预期产量
[('foo', 'bar'), ('breakfast', 'spam,eggs')]

我正在尝试使用regex,但面临以下问题:

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

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

因此,
我想我必须把最后一个逗号(或$)设为强制性的。
这样做并不真的管用,
r'([a-z_]+)=(.+?)(?:,|$)'
与省略逗号后面包含逗号的值一样,
e、 g.[('foo', 'bar'), ('breakfast', 'spam')]

我想我必须用某种方式看看后面操作。
问题
一。我要用哪一个?或
2。我该怎么做/怎么做?

编辑

根据下面daramarak的回答,
最后,我做了和abarnert之后的suggested几乎相同的事情,只是形式稍显冗长

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元组的列表?


Tags: in编辑forfoovaluebarspam事情
3条回答

daramarak的答案要么非常接近工作,要么就是按原样工作;很难从示例输出的格式和步骤的模糊描述中分辨出来。但如果它是非常接近工作的版本,它很容易修复。

输入代码:

>>> bits=[x.rsplit(',', 1) for x in s.split('=')]
>>> kv = [(bits[i][-1], bits[i+1][0]) for i in range(len(bits)-1)]

第一行是(我相信)达玛拉克的答案。第一行本身给您成对的(value_i, key_i+1),而不是(key_i, value_i)。第二行是最明显的解决方案。有了更多的中间步骤和一些输出,看看它是如何工作的:

>>> s = 'foo=bar,breakfast=spam,eggs,blt=bacon,lettuce,tomato,spam=spam'
>>> bits0 = s.split('=')
>>> bits0
['foo', 'bar,breakfast', 'spam,eggs,blt', 'bacon,lettuce,tomato,spam', 'spam']
>>> bits = [x.rsplit(',', 1) for x in bits0]
>>> bits
[('foo'), ('bar', 'breakfast'), ('spam,eggs', 'blt'), ('bacon,lettuce,tomato', 'spam'), ('spam')]
>>> kv = [(bits[i][-1], bits[i+1][0]) for i in range(len(bits)-1)]
>>> kv
[('foo', 'bar'), ('breakfast', 'spam,eggs'), ('blt', 'bacon,lettuce,tomato'), ('spam', 'spam')]

我能建议你像以前一样使用拆分操作吗。但是先在等号处拆分,然后在最右边的逗号处拆分,以生成一个左右字符串的列表。

input =
"bob=whatever,king=kong,banana=herb,good,yellow,thorn=hurts"

最初的分裂会变成

first_split = input.split("=")
#first_split = ['bob' 'whatever,king' 'kong,banana' 'herb,good,yellow,thorn' 'hurts']

然后在最右边的逗号处拆分可以得到:

second_split = [single_word for sublist in first_split for item in sublist.rsplit(",",1)]
#second_split = ['bob' 'whatever' 'king' 'kong' 'banana' 'herb,good,yellow' 'thorn' 'hurts']

然后你就这样收集这对:

pairs = dict(zip(second_split[::2],second_split[1::2]))

为了便于比较,这里有一个regex似乎也能解决这个问题:

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

这里的诀窍是限制你在第二组中捕获的内容。.+吞下=符号,这是用于区分键和值的字符。完整的regex不依赖于任何回溯(因此如果需要的话,它应该与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')]

相关问题 更多 >