正则表达式以键/值对解析定界字符串(Python)

时间:2019-05-25 16:17:54

标签: python regex regex-group

我有文本格式的数据,其中键/值对之间用分号分隔,后面可能跟空格,例如,可能不是“;”。或“;”,甚至“;”。线对之间始终会有分号,并且字符串以分号结尾。

键和值由空格分隔。

此字符串是扁平的。没有任何嵌套。字符串总是用引号引起来,而数值则不用引号引起来。我可以指望这在输入中保持一致。例如,

'cheese "stilton";pigeons 17; color "blue"; why "because I said so";'

最终,它以

结束
{'cheese': "stilton", 'pigeons': 17, 'color': "blue"; 'why': "because I said so"}

不同的字符串可能包含不同的键/值对,因此我无法事先知道将出现哪些键。因此,这是同样有效的输入字符串:

mass 6.02 ; mammal "gerbil";telephone "+1 903 555-1212"; size "A1";

我认为正则表达式将字符串拆分为一个列表是一个不错的开始,然后只需将列表遍历两次就可以构建字典。像

x = PATTERN.split(s)
d = {}
for i in range(0, len(x), 2):
    d[x[i]] = d[x[i+1]]

要求使用[[奶酪],[斯蒂尔顿],[鸽子],17,[颜色],[蓝色],[为什么],[因为我这么说]]这样的列表。但是我不知道要使用这种形式的正则表达式。我最近的是

([^;[\s]*]+)

哪个返回

['', 'cheese', ' ', '"stilton"', ';', 'pigeons', ' ', '17', '; ', 'color', ' ', '"blue"', '; ', 'why', ' ', '"because', ' ', 'I', ' ', 'said', ' ', 'so"', ';']

当然,通过三位迭代并选择键/值对并忽略捕获的定界符很容易,但是我想知道是否存在不捕获定界符的正则表达式。有什么建议吗?

2 个答案:

答案 0 :(得分:1)

在这里使用findall()而不是split()可能会更容易。这样,您就可以使用捕获组仅提取所需的部分。然后,您可以拆分组,清理等:

import re
s = 'cheese "stilton";pigeons 17; color "blue"; why "because I said so";'
pairs = re.findall(r'(\S+?) (.+?);', s)

d = {}
for k, v in pairs:
    if  v.isdigit():
        v = int(v)
    else:
        v = v.strip('"')
    d[k] = v
print(d)

结果

{'cheese': 'stilton',
 'pigeons': 17,
 'color': 'blue',
 'why': 'because I said so'}

这当然假定您不在数据中的任何地方使用;

答案 1 :(得分:1)

您可以使用

r'(\w+)\s+("[^"]*"|[^\s;]+)'

使用re.findall进行匹配和提取数据,并对第2组的值进行后处理以删除第一个和最后一个"字符,如果第一个备用字符匹配,则创建一个字典条目。 / p>

请参见regex demo

详细信息

  • (\w+)-第1组(键):一个或多个单词字符
  • \s+-1个以上的空格字符
  • ("[^"]*"|[^\s;]+)-第2组:",除"以外的0多个字符,然后为"或除空格和;以外的1个或更多字符

Python demo

import re
rx = r'(\w+)\s+("[^"]*"|[^\s;]+)'
s = 'cheese "stilton";pigeons 17; color "blue"; why "because I said so";'
result = {}
for key,val in re.findall(rx, s):
    if val.startswith('"') and val.endswith('"'):
        val = val[1:-1]
    result[key]=val

print(result)