漂亮的打印json,但将内部数组保留在一行python

Posted

技术标签:

【中文标题】漂亮的打印json,但将内部数组保留在一行python【英文标题】:Pretty print json but keep inner arrays on one line python 【发布时间】:2014-12-03 13:49:52 【问题描述】:

我非常喜欢使用以下代码在 Python 中打印一个 json:

json.dumps(json_output, indent=2, separators=(',', ': ')

这会打印出我的 json 格式:

    
    "rows_parsed": [
        [
          "a",
          "b",
          "c",
          "d"
        ],
        [
          "e",
          "f",
          "g",
          "i"
        ],
    ]

但是,我希望它打印如下:

    
    "rows_parsed": [
        ["a","b","c","d"],
        ["e","f","g","i"],
    ]

我怎样才能像上面一样将数组中的数组保持在一行上?

【问题讨论】:

请注意,您想要的输出不会将 all 数组保留在一行上。 好点。让我澄清一下我的问题。 (简单:)考虑pprint。 (难:)考虑编写一个自定义 JSONEncoder 并将其作为 cls 参数传递给 dumps。 (必须:)再想想你为什么需要这一切。 JSON dumps custom formatting的可能重复 您是想将“数组中的数组”全部保留在一行上,还是真的要保留 不包含其他数组或字典的数组一条线?后者似乎更自然。 【参考方案1】:

这是一种尽可能减少修改的方法:

import json
from json import JSONEncoder
import re

class MarkedList:
    _list = None
    def __init__(self, l):
        self._list = l

z =     
    "rows_parsed": [
        MarkedList([
          "a",
          "b",
          "c",
          "d"
        ]),
        MarkedList([
          "e",
          "f",
          "g",
          "i"
        ]),
    ]


class CustomJSONEncoder(JSONEncoder):
    def default(self, o):
        if isinstance(o, MarkedList):
            return "##<>##".format(o._list)

b = json.dumps(z, indent=2, separators=(',', ':'), cls=CustomJSONEncoder)
b = b.replace('"##<', "").replace('>##"', "")

print(b)

基本上,您希望以您创建实例的方式格式化的列表 MarkedList 并且它们被解析为具有希望足够唯一序列的字符串 后来从dumps 的输出中删除。这样做是为了消除 json 字符串周围的引号。

另一种更有效但更丑陋的方法是猴子补丁 json.encoder._make_iterencode._iterencode 类似:

def _iterencode(o, _current_indent_level):
    if isinstance(o, str):
        yield _encoder(o)
    elif o is None:
        yield 'null'
    elif o is True:
        yield 'true'
    elif o is False:
        yield 'false'
    elif isinstance(o, int):
        # see comment for int/float in _make_iterencode
        yield _intstr(o)
    elif isinstance(o, float):
        # see comment for int/float in _make_iterencode
        yield _floatstr(o)
    elif isinstance(o, MarkedList):
        yield _my_custom_parsing(o)
    elif isinstance(o, (list, tuple)):
        yield from _iterencode_list(o, _current_indent_level)
    elif isinstance(o, dict):
        yield from _iterencode_dict(o, _current_indent_level)
    else:
        if markers is not None:
            markerid = id(o)
            if markerid in markers:
                raise ValueError("Circular reference detected")
            markers[markerid] = o
        o = _default(o)
        yield from _iterencode(o, _current_indent_level)
        if markers is not None:
            del markers[markerid]

【讨论】:

【参考方案2】:

我看不出你怎么能在 json.dumps 中做到这一点。经过一番搜索,我遇到了一些选择: 一种选择是使用自定义函数进行一些后处理:

def fix_json_indent(text, indent=3):
            space_indent = indent * 4
    initial = " " * space_indent
    json_output = []
    current_level_elems = []
    all_entries_at_level = None  # holder for consecutive entries at exact space_indent level
    for line in text.splitlines():
        if line.startswith(initial):
            if line[space_indent] == " ":
                # line indented further than the level
                if all_entries_at_level:
                    current_level_elems.append(all_entries_at_level)
                    all_entries_at_level = None
                item = line.strip()
                current_level_elems.append(item)
                if item.endswith(","):
                    current_level_elems.append(" ")
            elif current_level_elems:
                # line on the same space_indent level
                # no more sublevel_entries 
                current_level_elems.append(line.strip())
                json_output.append("".join(current_level_elems))
                current_level_elems = []
            else:
                # line at the exact space_indent level but no items indented further
                if all_entries_at_level:
                    # last pending item was not the start of a new sublevel_entries.
                    json_output.append(all_entries_at_level)
                all_entries_at_level = line.rstrip()
        else:
            if all_entries_at_level:
                json_output.append(all_entries_at_level)
                all_entries_at_level = None
            if current_level_elems:
                json_output.append("".join(current_level_elems))
            json_output.append(line)
    return "\n".join(json_output)

另一种可能性是正则表达式,但它非常难看,并且取决于您发布的代码的结构:

def fix_json_indent(text):
    import re
    return  re.sub('"', '\n"', re.sub('\[\[', '[\n[', re.sub('\]\]', ']\n]', re.sub('', '\n', text))))

【讨论】:

以上是关于漂亮的打印json,但将内部数组保留在一行python的主要内容,如果未能解决你的问题,请参考以下文章

如何以漂亮的打印风格在 JSON 中编写数据框?

使用 Python 将 JSON 数据漂亮地打印到文件中

PHP“漂亮打印”json_encode [重复]

默认在 MongoDB shell 中打印漂亮

如何使用 Go 漂亮地打印 JSON?

Postgresql 复制在漂亮打印的 JSON 上失败