Python 如何截断dict中的数据以使生成的JSON不';长度不超过n字节?

Python 如何截断dict中的数据以使生成的JSON不';长度不超过n字节?,python,unicode,json,micro-optimization,Python,Unicode,Json,Micro Optimization,我有一个Python2.7 dict,比如{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 = (',',

我有一个Python2.7 dict,比如
{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
在我看来,应该有一种方法来优化这个!我真的是一次剥离一个角色,感觉很不对

我的问题非常接近,除了我使用Python2.7之外,只要源字符串包含非ASCII unicode字符,json编码器就会生成相当长的json字符串


另外,我很确定这将打破UTF-16代理项对…

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

然后选择尽可能多的元素,以获得所需的长度


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

如果你想让它变得更快(你不应该这样做,除非你知道这是你程序中的一个热点,需要付出真正的性能代价),你可以先猜出要剥离的字符数,然后处理剩余字符

首先,如果你需要去掉52个字符,其中有10个键,你需要从2个键中各去掉6个字符,从其他8个键中各去掉5个字符,对吗?当然,除了,你可能试图从只有4个字符长的东西中去掉6个字符,这意味着你最终仍然会超出限制2个字符。但是你可以在一个小时内跟踪这些剩余字符d完成后再处理它们。不太可能有足够的剩菜让“快”版本值得再做一次,所以你不妨使用“慢”版本

def payload_to_json(payload,max_size=256):
json_string=json.dumps(有效负载,分隔符=(',',':'))
chars_to_strip=len(json_字符串)-最大大小

如果chars_to_strip为什么不使用以下策略: 测量第一个生成的json,然后按照首选顺序从值中去掉适当数量的字符

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


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

您是说“优化”吗“在性能方面,还是在可读性方面?嗯,我说的是性能。我的代码不可读吗?不,我的观点是,如果你试图使它更快,它可能会变得不可读,这可能是不值得的。(作为一个例子,我认为你的代码比我的代码可读性好得多,不是吗?)。什么听起来真的是个坏主意?试图优化此代码?或者缩短字符串以适应256个字符的想法?我喜欢你的评论,我不应该试图优化这段代码。你可能是对的。只是感觉太不对了!;-)我很惊讶你这么快就想到了这一点,但我想先修剪最长的字符串,除非我必须修改短字符串。好的,这也是可行的。让我想一想。在英语中:第一种按长度排序(
排序(payload.items(),key=lambda item:-len(item[1]))
)。然后,您可以很容易地计算出通过截断每个长度可以节省多少,以O(N)摊销总时间为单位。因此,继续减少长度,直到
节省>=chars\u to\u strip
。然后,
underflow=savings-chars\u to\u strip
。在一次传递中,将最后一个
下溢
值截断为maxlen+1,将所有其他值截断为maxlen。然后将排序后的
列表
转换回
目录
。或者…不是截断
项[1]
,而是截断
有效负载[0]
,以节省转换回的成本。不管怎样,不用说,这也会比你原来的代码更复杂,更不可读,所以考虑它是否值得。我试着从另一个帖子中使用这个策略,但是因为没有ASCII字符,它并不是很好。例如,在我的示例中,这两个中文字符被编码为JSON字符串中的12个ASCII字符。因此,如果我应用建议的策略,我应该从一个字符串中删除12个字符,然后就什么都没有了。如果你想这样做,你需要两个步骤:首先
编码('unicode_escape')
负载中的所有内容,然后最小化转义负载。但你可能无论如何都想这么做,否则,每次你重新检查结果时,你都要为逃跑付出代价。(虽然我猜这比
json.dumps
便宜得多,但它仍然不是免费的。)在我看来,更简单的方法是计算
json.dumps()添加的字符数。。。鉴于您使用的dict是一维的!因此,您不必处理unicode,尽管它可能看起来很“黑客”…@Caessol:这样做,您将无法知道UTF-8-ifying添加了多少字符,JSON-ifying添加了多少字符。(此外,他显然希望在最终结果中使用unicode_escape而不是UTF-8。)@abarnert:通过排除,我知道JSON的化合添加了多少字符:
len(“{}”)+len(有效载荷)*len(“:”,”)-len(“,”)
。然后,类似这样的内容可以告诉您UTF8-ifying的情况:
len(''.join([k.encode('unicode\u escape')+v.encode('unicode\u escape'),表示有效负载中的k,v.iteritems())
。这难道不是比在整个dict中循环,在每一步提取一个字符并重新生成JSON更方便吗?
>>> 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)
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 = (',', ':'))