在 python 中截断 json 内的长字符串

Truncate long strings inside json in python

给定一些 json

[
    {
        "default_value": "True",
        "feature_name": "feature_1",
        "active_on": "remote_1,remote_2,remote_3,remote_4,remote_5,remote_6,remote_7"
    },
    {
        "feature_name": "special_super_duper_feature_wooooooooot",
        "active_on": "remote_2"
    }
]

如何截断超过 20 个字符的值:

[
    {
        "default_value": "True",
        "feature_name": "feature_1",
        "active_on": "remote_1,remote_2..."
    },
    {
        "feature_name": "special_super_dup...",
        "active_on": "remote_2"
    }
]

尽可能笼统?

编辑: 这是一个更通用的示例:

[
    {
        "a": {"b": "c"},
        "d": "e"
    },
    {
        "a": [{"b": "dugin-walrus-blowing-up-the-view-and-ruining-page-frame"}]
    }
]

这里的结局是为任意 json 制作“漂亮的印刷品”。 我想知道是否有仅使用标准库的好方法。

我不知道有任何 built-in 方法可以做到这一点,但一种方法可能是只遍历列表,然后遍历每个字典中的项目,并对每个项目应用一个字符串切片,像这样:

def truncate(d: dict):
    for k, v in d.items():
        d.update({k: str(v)[:17] + "..."})
    return d

json_trunc = list(map(lambda x: truncate(x), json_orig))

如果需要的话,肯定也可以在列表理解中包含截断函数,我只是在这里将它们分开以便于阅读/理解。

您可以通过这种方式使用字符串限制器:

[:17] + '...'

并在您的价值观中循环工作以重新调整其价值观。

示例:

a = 'test text to work with limiter length'
a = a[:17] + '...'
print(a)

结果:

test text to work...

这是我的看法:

import collections
...

def truncate_strings(obj: collections.abc.Iterable, truncate: int, suffix: str = "...") -> int:
    """
    @param obj: generic iterable  - object to truncate. Implemented for dicts and lists. 
                                    Extensible by adding new types to isinstance.
    @param truncate: int          - total str length to be set. value 0 to disable.
    @param suffix: str [Optional] - the truncation string suffix

    @returns count: int           - number of strings truncated 
    """

    if not truncate or not obj or isinstance(obj, str):
        return 0
    count = 0
    if isinstance(obj, dict):
        for key_ in obj.keys():
            if not key_:
                return 0
            if isinstance(obj.get(key_), str):
                if len(obj[key_]) > truncate - len(suffix):
                    count += 1
                    obj[key_] = obj[key_][:truncate - len(suffix)] + suffix
            else:
                count += truncate_strings(key_, truncate, suffix)
    elif isinstance(obj, collections.abc.Iterable):
        for item in obj:
            count += truncate_strings(item, truncate, suffix)
    return count

请注意,此函数在可迭代对象上是递归的,因此长列表会杀死您的调用堆栈。应该在合理的大小 jsons 上工作(在 1k 项目 json 数组上测试)