简单方法将字符串转换为字典
将一串“关键字=值”的字符串转换成字典,最简单的方法是什么呢?比如下面这个字符串:
name="John Smith", age=34, height=173.2, location="US", avatar=":,=)"
想要转换成下面这个Python字典:
{'name':'John Smith', 'age':34, 'height':173.2, 'location':'US', 'avatar':':,=)'}
这里提到的“avatar”这个键只是为了说明字符串中可以包含“=”和“,”,所以简单地用“分割”是行不通的。有没有什么好主意呢?谢谢!
10 个回答
我建议用一种懒惰的方法来实现这个。
test_string = 'name="John Smith", age=34, height=173.2, location="US", avatar=":,=)"'
eval("dict({})".format(test_string))
{'年龄': 34, '地点': '美国', '头像': ':,=)', '名字': '约翰·史密斯', '身高': 173.2}
希望这能帮到某个人!
编辑: 由于 csv
模块在处理字段内部的引号时效果不如预期,所以实现这个功能需要多花点功夫:
import re
quoted = re.compile(r'"[^"]*"')
class QuoteSaver(object):
def __init__(self):
self.saver = dict()
self.reverser = dict()
def preserve(self, mo):
s = mo.group()
if s not in self.saver:
self.saver[s] = '"%d"' % len(self.saver)
self.reverser[self.saver[s]] = s
return self.saver[s]
def expand(self, mo):
return self.reverser[mo.group()]
x = 'name="John Smith", age=34, height=173.2, location="US", avatar=":,=)"'
qs = QuoteSaver()
y = quoted.sub(qs.preserve, x)
kvs_strings = y.split(',')
kvs_pairs = [kv.split('=') for kv in kvs_strings]
kvs_restored = [(k, quoted.sub(qs.expand, v)) for k, v in kvs_pairs]
def converter(v):
if v.startswith('"'): return v.strip('"')
try: return int(v)
except ValueError: return float(v)
thedict = dict((k.strip(), converter(v)) for k, v in kvs_restored)
for k in thedict:
print "%-8s %s" % (k, thedict[k])
print thedict
我把 thedict
输出了两次,以便清楚地展示它和预期结果的不同;输出结果是:
age 34
location US
name John Smith
avatar :,=)
height 173.2
{'age': 34, 'location': 'US', 'name': 'John Smith', 'avatar': ':,=)',
'height': 173.19999999999999}
如你所见,当直接用 print
输出浮点数值时,结果是符合要求的,但当对整个 dict
使用 print
时,结果就不对了,且不可能正确显示(因为在这种情况下,根本没有浮点数值能显示为 173.2
!)这是因为 print
会对字典的键和值使用 repr
,而 173.2
的 repr
形式是这样的,考虑到浮点数在计算机中是以二进制存储的,而不是十进制等等。如果这是个必须的需求,你可以定义一个 dict
的子类,重写 __str__
方法,专门处理浮点数值。
不过,我希望这个小插曲不会影响到核心思想——只要双引号正确配对(并且没有双引号嵌套在双引号里面),这段代码确实能完成保护“特殊字符”(在这个例子中是逗号和等号)不被当作普通字符处理的任务,即使双引号是从“字段”内部开始的,而不是从字段的开头开始(csv
只处理后者的情况)。如果代码的工作方式不明显,可以插入一些中间的打印语句——首先,它会把所有“带双引号的字段”转换成一种特别简单的形式(比如 "0"
, "1"
等),同时单独记录这些简单形式对应的实际内容;最后,这些简单形式会被转换回原来的内容。字符串的双引号去除和未加引号的字符串转换为整数或浮点数的工作,最终由简单的 converter
函数来处理。
这个对我有效:
# get all the items
matches = re.findall(r'\w+=".+?"', s) + re.findall(r'\w+=[\d.]+',s)
# partition each match at '='
matches = [m.group().split('=', 1) for m in matches]
# use results to make a dict
d = dict(matches)