将keyword = values字符串转换为字典的最简单方法是什么,例如以下字符串:
name="John Smith", age=34, height=173.2, location="US", avatar=":,=)"
到以下python词典:
{'name':'John Smith', 'age':34, 'height':173.2, 'location':'US', 'avatar':':,=)'}
'avatar'键只是为了表明字符串可以包含=和,所以简单的'拆分'是不行的。有任何想法吗?谢谢!
答案 0 :(得分:9)
这对我有用:
# 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)
答案 1 :(得分:4)
修改:由于 我两次发出 如您所见,浮点值的输出与 但是,我希望这种分心不会干扰核心思想 - 只要双引号得到适当平衡(并且没有双引号 - 内部 - 双引号),这段代码确实执行了保留“特殊”的必要任务字符“(逗号和等号,在这种情况下),当它们在双引号内时,从正常意义上看,即使双引号开始在内”而不是在开头“该字段(csv
模块未按照字段字段中的引号进行处理,因此实现此功能需要更多工作:< / p>
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
直接发出时的请求相同,但不是,不能(因为 IS < / em>在这种情况下没有显示173.2
的浮点值! - )print
应用于整个dict
时(因为它不可避免地使用repr
考虑到浮点值如何以二进制存储,而不是以十进制等方式存储的常见问题,键和值 - 以及repr
的{{1}}具有该形式。您可以定义一个173.2
子类,它将dict
覆盖为特殊的浮点值,我想,如果这确实是一个要求。__str__
仅处理后一种情况)。如果代码的工作方式不明显,请插入一些中间打印 - 首先它将所有“双引号字段”更改为一个特殊的简单形式(csv
,"0"
等等),同时单独录制那些简单形式对应的实际内容是什么;最后,简单的表格被改回原来的内容。双引号剥离(对于字符串)以及将未加引号的字符串转换为整数或浮点数最终由简单的"1"
函数处理。
答案 2 :(得分:2)
这是使用pyparsing解决问题的更详细的方法。请注意解析操作 它将类型从字符串自动转换为整数或浮点数。而且, QuotedString类隐式地从引用的值中剥离引号。最后, Dict类在逗号分隔的列表中获取每个'key = val'组,并分配 结果名称使用键和值标记。
from pyparsing import *
key = Word(alphas)
EQ = Suppress('=')
real = Regex(r'[+-]?\d+\.\d+').setParseAction(lambda t:float(t[0]))
integer = Regex(r'[+-]?\d+').setParseAction(lambda t:int(t[0]))
qs = QuotedString('"')
value = real | integer | qs
dictstring = Dict(delimitedList(Group(key + EQ + value)))
现在解析原始文本字符串,将结果存储在dd中。 Pyparsing返回一个 ParseResults类型的对象,但是这个类有许多类似dict的特性(支持keys(), items(),in等),或者可以通过调用asDict()发出一个真正的Python dict。调用转储() 显示原始解析列表中的所有标记以及所有命名项。最后 两个示例显示了如何在ParseResults中访问命名项,就好像它们是属性一样 一个Python对象。
text = 'name="John Smith", age=34, height=173.2, location="US", avatar=":,=)"'
dd = dictstring.parseString(text)
print dd.keys()
print dd.items()
print dd.dump()
print dd.asDict()
print dd.name
print dd.avatar
打印:
['age', 'location', 'name', 'avatar', 'height']
[('age', 34), ('location', 'US'), ('name', 'John Smith'), ('avatar', ':,=)'), ('height', 173.19999999999999)]
[['name', 'John Smith'], ['age', 34], ['height', 173.19999999999999], ['location', 'US'], ['avatar', ':,=)']]
- age: 34
- avatar: :,=)
- height: 173.2
- location: US
- name: John Smith
{'age': 34, 'height': 173.19999999999999, 'location': 'US', 'avatar': ':,=)', 'name': 'John Smith'}
John Smith
:,=)
答案 3 :(得分:1)
以下代码生成正确的行为,但只是有点长!我在头像中添加了一个空格,以表明它可以很好地处理逗号和空格以及字符串中的等号。有什么建议可以缩短它吗?
import hashlib
string = 'name="John Smith", age=34, height=173.2, location="US", avatar=":, =)"'
strings = {}
def simplify(value):
try:
return int(value)
except:
return float(value)
while True:
try:
p1 = string.index('"')
p2 = string.index('"',p1+1)
substring = string[p1+1:p2]
key = hashlib.md5(substring).hexdigest()
strings[key] = substring
string = string[:p1] + key + string[p2+1:]
except:
break
d = {}
for pair in string.split(', '):
key, value = pair.split('=')
if value in strings:
d[key] = strings[value]
else:
d[key] = simplify(value)
print d
答案 4 :(得分:1)
以下是使用eval
的方法,我认为它虽然不可靠,但它适用于您的示例。
>>> import re
>>>
>>> s='name="John Smith", age=34, height=173.2, location="US", avatar=":,=)"'
>>>
>>> eval("{"+re.sub('(\w+)=("[^"]+"|[\d.]+)','"\\1":\\2',s)+"}")
{'age': 34, 'location': 'US', 'name': 'John Smith', 'avatar': ':,=)', 'height': 173.19999999999999}
>>>
<强>更新强>
更好地使用Chris Lutz在评论中指出的那个,我相信它更可靠,因为即使dict值中有(单/双)引号,它也可能有用。
答案 5 :(得分:1)
这是一个更强大的正则表达式解决方案版本:
import re
keyval_re = re.compile(r'''
\s* # Leading whitespace is ok.
(?P<key>\w+)\s*=\s*( # Search for a key followed by..
(?P<str>"[^"]*"|\'[^\']*\')| # a quoted string; or
(?P<float>\d+\.\d+)| # a float; or
(?P<int>\d+) # an int.
)\s*,?\s* # Handle comma & trailing whitespace.
|(?P<garbage>.+) # Complain if we get anything else!
''', re.VERBOSE)
def handle_keyval(match):
if match.group('garbage'):
raise ValueError("Parse error: unable to parse: %r" %
match.group('garbage'))
key = match.group('key')
if match.group('str') is not None:
return (key, match.group('str')[1:-1]) # strip quotes
elif match.group('float') is not None:
return (key, float(match.group('float')))
elif match.group('int') is not None:
return (key, int(match.group('int')))
它会自动转换花车和投注到正确的类型;处理单引号和双引号;处理不同位置的无关空白;并且如果提供格式错误的字符串则会抱怨
>>> s='name="John Smith", age=34, height=173.2, location="US", avatar=":,=)"'
>>> print dict(handle_keyval(m) for m in keyval_re.finditer(s))
{'age': 34, 'location': 'US', 'name': 'John Smith', 'avatar': ':,=)', 'height': 173.19999999999999}
答案 6 :(得分:1)
我建议采用一种懒惰的方法。
test_string = 'name="John Smith", age=34, height=173.2, location="US", avatar=":,=)"'
eval("dict({})".format(test_string))
{'age':34,'location':'US','avatar':':,=)','name':'John Smith','height':173.2}
希望这有助于某人!
答案 7 :(得分:0)
我认为您只需要设置maxsplit = 1,例如以下内容应该有效。
string = 'name="John Smith", age=34, height=173.2, location="US", avatar=":, =)"'
newDict = dict(map( lambda(z): z.split("=",1), string.split(", ") ))
编辑(见评论):
我没有注意到“,”是头像下的一个值,最好的方法是逃避“,”无论你在哪里生成数据。更好的是像JSON;)。但是,作为regexp的替代方案,您可以尝试使用shlex,我认为它可以生成更清晰的代码。
import shlex
string = 'name="John Smith", age=34, height=173.2, location="US", avatar=":, =)"'
lex = shlex.shlex ( string )
lex.whitespace += "," # Default whitespace doesn't include commas
lex.wordchars += "." # Word char should include . to catch decimal
words = [ x for x in iter( lex.get_token, '' ) ]
newDict = dict ( zip( words[0::3], words[2::3]) )
答案 8 :(得分:0)
一步一步地进行
d={}
mystring='name="John Smith", age=34, height=173.2, location="US", avatar=":,=)"';
s = mystring.split(", ")
for item in s:
i=item.split("=",1)
d[i[0]]=i[-1]
print d
答案 9 :(得分:-2)
始终以逗号分隔?使用CSV模块将线分成多个部分(未选中):
import csv
import cStringIO
parts=csv.reader(cStringIO.StringIO(<string to parse>)).next()