1

我已经找到了如何在其他地方的字典中将分隔字符串拆分为键:值对,但是我有一个传入的字符串,其中还包含两个相当于字典本身的参数:其中包含一个或三个键:值对的参数:

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

并添加第三级来处理和保存第二级字典?语法是什么?如果不是,我想我将不得不拆分&,然后检查并处理包含:但即使这样我也无法弄清楚语法的拆分。有人可以帮忙吗?谢谢!

4

3 回答 3

2

我基本上接受了凯尔的回答,并使它对未来更加友好:

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
于 2012-12-06T22:51:01.097 回答
1

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

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

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

即使这样也可能有点太聪明了;我可能会更明确地检查“这是字典格式吗”,而不是仅仅尝试转换列表列表并查看会发生什么。

无论哪种方式,您如何将其放回您最初的理解中?

好吧,你想在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生成器表达式。如果它可以重写为字典推导式,那几乎肯定会更清晰,如果它不能改写为字典推导式,那么它可能一开始就不应该是一个单行表达式。

当然,将表达式分解为单独的表达式,将其中的一些变成语句甚至函数,并命名它们确实会使您的代码更长——但这并不一定意味着更糟。大约一半的 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. 哪个序列?不知道。你必须一步一步地分解它,看看什么不起作用。这不好玩。

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

于 2012-12-06T21:57:40.913 回答
1

这是一个两班轮,可以做我认为你想要的:

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('&'))
于 2012-12-06T22:14:55.033 回答