[英]Parse string with three-level delimitation into dictionary
我已经找到了如何将分隔的字符串拆分为其他地方的字典中的键:值对,但我有一个传入的字符串,其中还包含两个参数,这些参数相当于字典本身:带有一个或三个键的参数:内部的值对:
clientid=b59694bf-c7c1-4a3a-8cd5-6dad69f4abb0&keyid=987654321&userdata=ip:192.168.10.10,deviceid:1234,optdata:75BCD15&md=AMT-Cam:avatar&playbackmode=st&ver=6&sessionid=&mk=PC&junketid=1342177342&version=6.7.8.9012
显然,这些是用于混淆专有代码的虚拟参数。 我想将所有这些转储到字典中,其中userdata
和md
键的值本身就是字典:
requestdict {'clientid' : 'b59694bf-c7c1-4a3a-8cd5-6dad69f4abb0', 'keyid' : '987654321', 'userdata' : {'ip' : '192.168.10.10', 'deviceid' : '1234', 'optdata' : '75BCD15'}, 'md' : {'Cam' : 'avatar'}, 'playbackmode' : 'st', 'ver' : '6', 'sessionid' : '', 'mk' : 'PC', 'junketid' : '1342177342', 'version' : '6.7.8.9012'}
我可以使用我发现的灵活的两级分隔解析命令:
requestDict = dict(line.split('=') for line in clientRequest.split('&'))
并为其添加第三级来处理和保存二级词典? 语法是什么? 如果没有,我想我将不得不拆分&
然后检查和处理包含的分裂:
但即使这样我也无法弄清楚语法。 有人可以帮忙吗? 谢谢!
我基本上接受了凯尔的回答并使其更加适合未来:
def dictelem(input):
parts = input.split('&')
listing = [part.split('=') for part in parts]
result = {}
for entry in listing:
head, tail = entry[0], ''.join(entry[1:])
if ':' in tail:
entries = tail.split(',')
result.update({ head : dict(e.split(':') for e in entries) })
else:
result.update({head: tail})
return result
我可以使用我发现的灵活的两级分隔解析命令:
requestDict = dict(line.split('=') for line in clientRequest.split('&'))
并为其添加第三级来处理和保存二级词典?
当然你可以,但是(a)你可能不想这样,因为超出两个级别的嵌套理解往往变得难以理解,而且(b)这种超级简单的语法不适用于像你这样的情况,其中只有一些数据可以变成一个字典。
例如, 'PC'
会发生什么? 你想把它变成{'PC': None}
吗? 或者可能是set
{'PC'}
? 或list
['PC']
? 或者只是不管它? 你必须决定并为此编写逻辑,并尝试将其作为表达式编写,这将使你的决定很难阅读。
所以,让我们把这个逻辑放在一个单独的函数中:
def parseCommasAndColons(s):
bits = [bit.split(':') for bit in s.split(',')]
try:
return dict(bits)
except ValueError:
return bits
这将返回一个dict
就像{'ip': '192.168.10.10', 'deviceid': '1234', 'optdata': '75BCD15'}
或{'AMT-Cam': 'avatar'}
的情况下,每个逗号-separated组件里面有一个冒号,但有一个像['1342177342']
这样的list
对于其中任何一个没有的情况。
即使这可能有点过于聪明; 我可能会使“这是字典格式”检查更明确,而不是只是尝试转换列表列表,看看会发生什么。
无论哪种方式,你如何将它重新融入你原来的理解中?
好吧,你想在line.split('=')
的值上调用它。 所以让我们为此添加一个函数:
def parseCommasAndColonsForValue(keyvalue):
if len(keyvalue) == 2:
return keyvalue[0], parseCommasAndColons(keyvalue[1])
else:
return keyvalue
requestDict = dict(parseCommasAndColonsForValue(line.split('='))
for line in clientRequest.split('&'))
最后一件事:除非你需要在旧版本的Python上运行,否则你不应该经常在生成器表达式上调用dict
。 如果它可以被重写为字典理解,那几乎肯定会更清楚,如果它不能被重写为字典理解,它可能不应该是一线表达式。
当然,将表达式分解为单独的表达式,将其中的一些转换为语句甚至函数,并命名它们确实会使代码更长 - 但这并不一定意味着更糟。 大约一半的禅宗( import this
)致力于解释原因。 或者引用Guido的一句话:“Python故意代码打高尔夫球。”
如果你真的想知道它会是什么样子,让我们把它分成两步:
>>> {k: [bit2.split(':') for bit2 in v.split(',')] for k, v in (bit.split('=') for bit in s.split('&'))}
{'clientid': [['b59694bf-c7c1-4a3a-8cd5-6dad69f4abb0']],
'junketid': [['1342177342']],
'keyid': [['987654321']],
'md': [['AMT-Cam', 'avatar']],
'mk': [['PC']],
'playbackmode': [['st']],
'sessionid': [['']],
'userdata': [['ip', '192.168.10.10'],
['deviceid', '1234'],
['optdata', '75BCD15']],
'ver': [['6']],
'version': [['6.7.8.9012']]}
这说明了为什么你不能只为内层添加一个dict
调用 - 因为大多数事情实际上不是字典,因为它们没有冒号。 如果你改变了,那就是这样:
{k: dict(bit2.split(':') for bit2 in v.split(',')) for k, v in (bit.split('=') for bit in s.split('&'))}
我不认为这是非常可读的,我怀疑大多数Python程序员会这样做。 从现在起6个月读它并试图找出我的意思比写它要花费更多的精力。
并尝试调试它将不会很有趣。 如果你在输入上运行那个冒号缺少会发生什么? ValueError: dictionary update sequence element #0 has length 1; 2 is required
ValueError: dictionary update sequence element #0 has length 1; 2 is required
。 哪个序列? 不知道。 你必须一步一步地分解它,看看哪些不起作用。 这没什么好玩的。
所以,希望这说明了为什么你不想这样做。
这是一个双线,可以做我想你想要的:
dictelem = lambda x: x if ':' not in x[1] else [x[0],dict(y.split(':') for y in x[1].split(','))]
a = dict(dictelem(x.split('=')) for x in input.split('&'))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.