2

我有一个 python 2.7 字典,例如{u"eat": u"糖果", u"drink": u"café"},我需要使用 JSON 传输它。JSON 字符串必须是常规 ASCII,并且必须少于 256 个字符。

到目前为止,我已经编写了这个代码:

import json

def payload_to_json(payload, max_size = 256):
    while True:
        json_string = json.dumps(payload, separators = (',', ':'))
        if len(json_string) <= max_size:
            return json_string
        max_length, found_key = 0, None
        for key, value in payload.iteritems():
            length = len(value)
            if length > max_length:
                max_length = length
                found_key = key
        if max_length == 0:
            return "" # just in case max_size is really low
        payload[found_key] = payload[found_key][:-1] # remove one char

它按预期工作:

>>> payload = {u"eat": u"糖果", u"drink": u"café"}
>>> print payload_to_json(payload)
{"drink":"caf\u00e9","eat":"\u7cd6\u679c"}
>>> print payload_to_json(payload, max_size=41)
{"drink":"caf","eat":"\u7cd6\u679c"}
>>> print payload_to_json(payload, max_size=35)
{"drink":"ca","eat":"\u7cd6\u679c"}
>>> print payload_to_json(payload, max_size=34)
{"drink":"c","eat":"\u7cd6\u679c"}
>>> print payload_to_json(payload, max_size=30)
{"drink":"c","eat":"\u7cd6"}
>>> print payload_to_json(payload, max_size=21)
{"drink":"","eat":""}
>>> print payload_to_json(payload, max_size=20)

在我看来,应该有一种方法来优化它!我真的一次剥一个角色,感觉很不对劲。

我的问题非常接近这个问题,除了我使用 python 2.7,而且只要源字符串包含非 ASCII unicode 字符,json 编码器就会产生相当长的 JSON 字符串。

另外,我很确定这将与 UTF-16 代理对中断......

4

3 回答 3

1

如果你试图让它更快(你不应该这样做,除非你知道这是你程序中的一个热点,会带来实际的性能成本),你可以先猜测要剥离的字符数,然后处理剩余部分.

首先,如果您需要去除 52 个字符,并且有 10 个键,则需要从 2 个键中分别去除 6 个字符,从其他 8 个键中分别去除 5 个字符,对吧?当然,除了你可能试图从只有 4 个字符长的东西中删除 6 个字符,这意味着你最终仍然会超出限制 2 个字符。但是您可以跟踪这些剩菜并在完成后处理它们。不太可能有足够的剩菜来通过“快速”版本进行另一次值得做的事情,因此您不妨只使用“慢速”版本。

def payload_to_json(payload, max_size = 256):
    json_string = json.dumps(payload, separators = (',', ':'))
    chars_to_strip = len(json_string) - max_size
    if chars_to_strip <= 0:
        return json_string
    key_count = len(payload)
    chars_per_key, extras = divmod(chars_to_strip, key_count)
    leftover = 0
    for i, key in enumerate(payload):
        to_strip = chars_per_key + (i < extras)
        orig_len = len(payload[key])
        if orig_len < to_strip:
            payload[key] = ''
            leftover += to_strip - orig_len
        else:
            payload[key] = payload[key][:-to_strip]
    if leftover:
        return slow_payload_to_json(payload, max_size)
    else:
        return json.dumps(payload, separators = (',', ':'))

我不确定这是否会在您的用例中加快速度。对于非常小的物体和最大尺寸,如果它真的减慢了速度,我不会感到惊讶。但是对于超过最大尺寸的巨大物体,它可能会有很大帮助。

于 2013-03-02T00:14:06.837 回答
0

如何计算每个条目的序列化大小

然后选择尽可能多的元素以达到所需的长度?

无论哪种方式,这听起来都是一个非常糟糕的主意。

于 2013-03-02T00:06:32.310 回答
0

为什么不使用链接的帖子中的策略:测量第一个生成的 json,然后按首选顺序从值中删除适量的字符。

否则,您可以通过计数来猜测 json 使用的字符数:对于每个映射变量,这些字符"":"",加上整体{},减去逗号。(除非你没有更复杂的嵌套列表,显然)

只要您使用u''符号,unicode 功能就不应该成为问题(不确定,但应该不难检查)

于 2013-03-02T00:27:04.500 回答