将具有三级分隔的字符串解析到字典中

2024-06-06 12:24:55 发布

您现在位置:Python中文网/ 问答频道 /正文

我找到了如何将分隔字符串拆分为键:值对在字典elsewhere中,但是我有一个传入字符串,它还包括两个相当于字典本身的参数:一个或三个参数的参数键:值对内部:

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键的值本身就是字典:

^{pr2}$

我可以使用我发现的光滑的两级定界解析命令吗:

requestDict = dict(line.split('=') for line in clientRequest.split('&'))

并添加第三级来处理和保留第二级词典?语法是什么?如果不是,我想我将不得不按&拆分,然后检查并处理包含:的拆分,但即使这样,我也无法找出语法。有人能帮忙吗?谢谢!在


Tags: 字符串ip参数字典line语法mdsplit
3条回答

这里有一个双行程序,我想它可以满足您的需要:

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('&'))

Can I take the slick two-level delimitation parsing command that I've found:

requestDict = dict(line.split('=') for line in clientRequest.split('&'))

and add a third level to it to handle & preserve the 2nd-level dictionaries?

当然可以,但是(a)你可能不想,因为超过两个级别的嵌套理解往往变得不可读,(b)这种超简单的语法不适用于像您这样只有部分数据可以转换为dict的情况

例如,'PC'应该发生什么?你想把它变成{'PC': None}?或者是set{'PC'}?还是list['PC']?还是别管它?你必须做出决定,并为此写下逻辑,试图把它写成表达式会让你的决定变得很难理解。在

那么,让我们把这个逻辑放到一个单独的函数中:

^{pr2}$

对于每个逗号分隔的组件内部都有一个冒号的情况,这将返回一个dict类似{'ip': '192.168.10.10', 'deviceid': '1234', 'optdata': '75BCD15'}或{},但对于其中任何一个没有的情况,则返回一个list类似['1342177342']

即使这样做也可能有点太聪明了;我可能会使“Isthisindictionary format”检查更加明确,而不是仅仅尝试转换列表列表,然后看看会发生什么。在

不管怎样,你会怎么把它还原成你最初的理解?在

好吧,你想调用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。如果它能被改写为字典理解,那么它几乎肯定会更清楚,如果它不能被改写为字典理解,它可能一开始就不应该是一个1行表达式。在

当然,将表达式分解为单独的表达式,将其中一些表达式转换为语句甚至函数,并对它们进行命名确实会使代码更长,但这并不一定意味着更糟。Python的禅宗思想(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。哪个序列?不知道。你必须一步一步地把它分解,看什么不起作用。一点也不好玩。在

所以,希望这能说明你为什么不想这么做。在

我基本上采用了Kyle's answer并使其更适合未来:

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

相关问题 更多 >