source

json을 예쁘게 인쇄하지만 내부 어레이를 한 줄에 유지

ittop 2023. 3. 13. 20:53
반응형

json을 예쁘게 인쇄하지만 내부 어레이를 한 줄에 유지

이 코드를 사용하여 Python에서 json을 인쇄하고 있습니다.

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

그러면 다음과 같이 내 아들이 인쇄됩니다.

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

다만, 다음과 같이 인쇄해 주세요.

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

어레이에 있는 어레이를 위와 같이 모두 한 줄로 유지하려면 어떻게 해야 합니까?

다음은 가능한 한 적은 양의 수정으로 이를 수행하는 방법입니다.

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]

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)

다른 방법으로는 regex를 생각할 수 있지만 매우 보기 흉하고 게시한 코드의 구조에 따라 달라집니다.

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

언급URL : https://stackoverflow.com/questions/26264742/pretty-print-json-but-keep-inner-arrays-on-one-line-python

반응형