繁体   English   中英

将具有三级定界的字符串解析为字典

[英]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

显然,这些是用于混淆专有代码的虚拟参数。 我想将所有这些转储到字典中,其中userdatamd键的值本身就是字典:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM