在 Python 中将分号分隔的字符串拆分为字典
Posted
技术标签:
【中文标题】在 Python 中将分号分隔的字符串拆分为字典【英文标题】:Splitting a semicolon-separated string to a dictionary, in Python 【发布时间】:2010-09-16 06:09:39 【问题描述】:我有一个如下所示的字符串:
"Name1=Value1;Name2=Value2;Name3=Value3"
在 Python 中是否有一个内置的类/函数会接受该字符串并构造一个字典,就好像我已经这样做了:
dict =
"Name1": "Value1",
"Name2": "Value2",
"Name3": "Value3"
我浏览了可用的模块,但似乎找不到任何匹配的内容。
谢谢,我确实知道如何自己编写相关代码,但由于这种小型解决方案通常是等待发生的雷区(即有人写道:Name1='Value1=2';)等等,所以我通常更喜欢一些预先测试的功能。
那我自己做吧。
【问题讨论】:
你的问题是否需要支持s = r'Name1='Value=2';Name2=Value2;Name3=Value3;Name4="Va\"lue;\n3"'
输入(注意:带引号的字符串中的分号,使用反斜杠转义引号,使用\n
转义,使用单引号和双引号)?
我的这个问题已经超过 6 年了,涉及这个问题的代码早就被替换了:) 不,它不需要支持引号。我只是想拥有一个预构建的功能,而不是自己编写一些东西。但是,代码早已不复存在。
【参考方案1】:
没有内置函数,但您可以通过生成器理解相当简单地完成此操作:
s= "Name1=Value1;Name2=Value2;Name3=Value3"
dict(item.split("=") for item in s.split(";"))
[编辑]从您的更新中,您表明您可能需要处理引用。这确实使事情复杂化,具体取决于您要查找的确切格式(接受哪些引号字符,哪些转义字符等)。您可能想查看 csv 模块,看看它是否可以覆盖您的格式。这是一个示例:(请注意,此示例的 API 有点笨拙,因为 CSV 旨在遍历一系列记录,因此我进行 .next() 调用只是为了查看第一行。调整为满足您的需求):
>>> s = "Name1='Value=2';Name2=Value2;Name3=Value3"
>>> dict(csv.reader([item], delimiter='=', quotechar="'").next()
for item in csv.reader([s], delimiter=';', quotechar="'").next())
'Name2': 'Value2', 'Name3': 'Value3', 'Name1': 'Value1=2'
但是,根据格式的确切结构,您可能需要编写自己的简单解析器。
【讨论】:
代码不处理引用,尝试:s = "Name1='Value;2';Name2=Value2;Name3=Value3"
(注意:引用的Name1
值中的分号)。
我不知道为什么第二个示例会为我抛出 AttributeError: '_csv.reader' object has no attribute 'next'
。当然我做了import csv
。
@Brian 有没有办法将值存储为整数而不是字符串?
怎么能反过来呢@Brain【参考方案2】:
这接近于做你想做的事:
>>> import urlparse
>>> urlparse.parse_qs("Name1=Value1;Name2=Value2;Name3=Value3")
'Name2': ['Value2'], 'Name3': ['Value3'], 'Name1': ['Value1']
【讨论】:
如果输入中有&
或%
则会中断。
@jfs 但字符串不包含其中任何一个。
@VishalSingh:*** 上的大多数访问者都来自谷歌,因此这里的答案不仅适用于提出问题的原始发帖人。如果我来这里是为了寻找如何在 Python 中将“分号分隔的字符串解析为字典”,那么我的字符串可能包含 &
或 %
——至少,值得一提的是,答案没有不适用于此类字符串。【参考方案3】:
easytiger $ cat test.out test.py | sed 's/^/ /'
p_easytiger_quoting:1.84563302994
'Name2': 'Value2', 'Name3': 'Value3', 'Name1': 'Value1'
p_brian:2.30507516861
'Name2': 'Value2', 'Name3': "'Value3'", 'Name1': 'Value1'
p_kyle:7.22536420822
'Name2': ['Value2'], 'Name3': ["'Value3'"], 'Name1': ['Value1']
import timeit
import urlparse
s = "Name1=Value1;Name2=Value2;Name3='Value3'"
def p_easytiger_quoting(s):
d =
s = s.replace("'", "")
for x in s.split(';'):
k, v = x.split('=')
d[k] = v
return d
def p_brian(s):
return dict(item.split("=") for item in s.split(";"))
def p_kyle(s):
return urlparse.parse_qs(s)
print "p_easytiger_quoting:" + str(timeit.timeit(lambda: p_easytiger_quoting(s)))
print p_easytiger_quoting(s)
print "p_brian:" + str(timeit.timeit(lambda: p_brian(s)))
print p_brian(s)
print "p_kyle:" + str(timeit.timeit(lambda: p_kyle(s)))
print p_kyle(s)
【讨论】:
这不能回答问题,因为它不处理引用。尝试s = "Name1='Value1=2';Name2=Value2" and
csv`(如布莱恩接受的答案)或parse_qs
(如凯尔的)会得到正确的,而你的会提出ValueError
。 OP 特别指出“如此小的解决方案通常是等待发生的雷区”,这就是他想要一个内置或其他经过良好测试的解决方案的原因,他给出了一个会破坏您的代码的示例。
啊,我没看到。仍然。在迭代发生之前预解析主字符串中的内容并调用替换函数数千次,它仍然比所有解决方案都要快。我会更新
我不确定你将如何准备它。但即使你这样做,这似乎正是 OP 在一个简单的解决方案中所害怕的。你确定前面没有其他地雷吗?你能证明它让 OP 满意吗?
好的,既然我已经看到了你的编辑……首先,s.replace
根本没有做任何事情;它只是返回一个您忽略的新字符串。其次,即使你做对了(s = s.replace…
),也不能解决问题,它只是在上面添加了一个新问题。在我的示例或 OP 上尝试一下。
规范明确包括处理他在问题Name='Value1=2';
中提到的示例输入。而且您的代码无法处理它。而且我不确定你会如何清理它而不以某种方式解析它,这将与 urlparse
或 csv
首先一样慢。【参考方案4】:
如果您的 Value1、Value2 只是实际值的占位符,您还可以将 dict()
函数与 eval()
结合使用。
>>> s= "Name1=1;Name2=2;Name3='string'"
>>> print eval('dict('+s.replace(';',',')+')')
'Name2: 2, 'Name3': 'string', 'Name1': 1
这是因为dict()
函数理解语法dict(Name1=1, Name2=2,Name3='string')
。字符串中的空格(例如,在每个分号之后)被忽略。但请注意,字符串值确实需要引用。
【讨论】:
谢谢,支持 string.replace 效果很好。不知道为什么我不能分开。我在 tc 框上做了 i = textcontrol.GetValue(),然后 o = i.split(';') 但没有输出一个字符串,只是抱怨格式,不像替换。s.replace(';'
-based 解决方案如果在引用值中有 ;
,则会中断。 eval is evil 在这种情况下是不必要的。【参考方案5】:
可以简单地通过字符串连接和列表推导来完成
",".join(["%s=%s" % x for x in d.items()])
>>d = 'a':1, 'b':2
>>','.join(['%s=%s'%x for x in d.items()])
>>'a=1,b=2'
【讨论】:
【参考方案6】:s1 = "Name1=Value1;Name2=Value2;Name3=Value3"
dict(map(lambda x: x.split('='), s1.split(';')))
【讨论】:
以上是关于在 Python 中将分号分隔的字符串拆分为字典的主要内容,如果未能解决你的问题,请参考以下文章