JSON 모듈을 사용하여 예쁘게 인쇄할 때 사용자 지정 들여쓰기를 구현하는 방법은 무엇입니까?
Python 2.7을 json
합니다.
'layer1': {
'layer2': {
'layer3_1': [ long_list_of_stuff ],
'layer3_2': 'string'
}
}
문제는 다음과 같이 예쁜 인쇄로 모든 것을 인쇄하고 있다는 것입니다.
json.dumps(data_structure, indent=2)
좋아요, 하지만 모든 걸 들여쓰려고 하는데, 안에 있는 내용만 빼고요."layer3_1"
하는 방대한 각 의 값을 과 같은 의 파일이 - 좌좌좌나나나 — — — — — with with with with with with with with — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — 。따라서 각 사전마다 하나의 값을 설정하면 다음과 같은 수천 줄의 파일을 인쇄할 수 있습니다.
{
"layer1": {
"layer2": {
"layer3_1": [
{
"x": 1,
"y": 7
},
{
"x": 0,
"y": 4
},
{
"x": 5,
"y": 3
},
{
"x": 6,
"y": 9
}
],
"layer3_2": "string"
}
}
}
제가 정말 원하는 것은 다음과 같습니다.
{
"layer1": {
"layer2": {
"layer3_1": [{"x":1,"y":7},{"x":0,"y":4},{"x":5,"y":3},{"x":6,"y":9}],
"layer3_2": "string"
}
}
}
'', '연장', '연장'이 json
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★"layer3_1"
? ?만약 그렇다면, 누가 방법을 가르쳐 주시겠습니까?
(주의: 이 답변의 코드는 다음과 같이 동작합니다.json.dumps()
JSON 형식의 문자열을 반환하지만,json.dump()
파일 같은 오브젝트에 직접 씁니다.JSON 파일에 2차원 목록 쓰기 질문에 대한 제 답변에 모두 적용되는 수정된 버전이 있습니다.)
갱신필
아래는 몇 번인가 수정한 제 답변의 버전입니다.J.F.에서 첫 번째 아이디어를 얻는 방법을 보여주기 위해 올린 원본과 달리.작품에 대한 세바스찬의 답변은 그의 답변과 마찬가지로 객체에 대한 의도되지 않은 문자열 표현을 반환했습니다.최신 업데이트 버전은 분리된 형식의 Python 개체 JSON을 반환합니다.
입니다.dict
OP의 중 순서로 단, OP의 코멘트는 OP의 코멘트 중 하나로 됩니다.sort_keys=True
는 첫 인수로 합니다.json.dumps()
프로세스를 호출하고, 더 이상 객체 유형을 따라 문자열로 변경할 수 없습니다.호출을 통해 프로세스가 진행되며, 이로 인해 개체 유형이 도중에 문자열로 변경되지 않습니다.다른 말로 표현되는 "포장" 개체가 현재 유지된다. 형 제 지 체 이 is in otherpped"유유다 words, type실 maintained object "객wra the now니" the됩 of즉
제 투고의 본래 의도를 이해하지 못한 결과 많은 사람들이 반대표를 던졌다고 생각합니다.그 때문에, 저는 몇번이나 「고정」해, 답변을 개선했습니다.현재 버전은 저의 원래 답변과 @Erik Allik이 답변에서 사용한 아이디어의 일부와 이 답변 아래의 코멘트에 표시된 다른 사용자들의 유용한 피드백을 혼합한 것입니다.
다음 코드는 Python 2.7.16과 3.7.4 모두에서 변경되지 않고 작동하는 것으로 보입니다.
from _ctypes import PyObj_FromPtr
import json
import re
class NoIndent(object):
""" Value wrapper. """
def __init__(self, value):
self.value = value
class MyEncoder(json.JSONEncoder):
FORMAT_SPEC = '@@{}@@'
regex = re.compile(FORMAT_SPEC.format(r'(\d+)'))
def __init__(self, **kwargs):
# Save copy of any keyword argument values needed for use here.
self.__sort_keys = kwargs.get('sort_keys', None)
super(MyEncoder, self).__init__(**kwargs)
def default(self, obj):
return (self.FORMAT_SPEC.format(id(obj)) if isinstance(obj, NoIndent)
else super(MyEncoder, self).default(obj))
def encode(self, obj):
format_spec = self.FORMAT_SPEC # Local var to expedite access.
json_repr = super(MyEncoder, self).encode(obj) # Default JSON.
# Replace any marked-up object ids in the JSON repr with the
# value returned from the json.dumps() of the corresponding
# wrapped Python object.
for match in self.regex.finditer(json_repr):
# see https://stackoverflow.com/a/15012814/355230
id = int(match.group(1))
no_indent = PyObj_FromPtr(id)
json_obj_repr = json.dumps(no_indent.value, sort_keys=self.__sort_keys)
# Replace the matched id string with json formatted representation
# of the corresponding Python object.
json_repr = json_repr.replace(
'"{}"'.format(format_spec.format(id)), json_obj_repr)
return json_repr
if __name__ == '__main__':
from string import ascii_lowercase as letters
data_structure = {
'layer1': {
'layer2': {
'layer3_1': NoIndent([{"x":1,"y":7}, {"x":0,"y":4}, {"x":5,"y":3},
{"x":6,"y":9},
{k: v for v, k in enumerate(letters)}]),
'layer3_2': 'string',
'layer3_3': NoIndent([{"x":2,"y":8,"z":3}, {"x":1,"y":5,"z":4},
{"x":6,"y":9,"z":8}]),
'layer3_4': NoIndent(list(range(20))),
}
}
}
print(json.dumps(data_structure, cls=MyEncoder, sort_keys=True, indent=2))
출력:
{
"layer1": {
"layer2": {
"layer3_1": [{"x": 1, "y": 7}, {"x": 0, "y": 4}, {"x": 5, "y": 3}, {"x": 6, "y": 9}, {"a": 0, "b": 1, "c": 2, "d": 3, "e": 4, "f": 5, "g": 6, "h": 7, "i": 8, "j": 9, "k": 10, "l": 11, "m": 12, "n": 13, "o": 14, "p": 15, "q": 16, "r": 17, "s": 18, "t": 19, "u": 20, "v": 21, "w": 22, "x": 23, "y": 24, "z": 25}],
"layer3_2": "string",
"layer3_3": [{"x": 2, "y": 8, "z": 3}, {"x": 1, "y": 5, "z": 4}, {"x": 6, "y": 9, "z": 8}],
"layer3_4": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
}
}
}
bodge. 단, dumps()에서 문자열을 얻으면 그 내용의 형식을 확실히 알 수 있는 경우 정규 표현 치환을 실행할 수 있습니다.다음과 같은 것들이 있습니다.
s = json.dumps(data_structure, indent=2)
s = re.sub('\s*{\s*"(.)": (\d+),\s*"(.)": (\d+)\s*}(,?)\s*', r'{"\1":\2,"\3":\4}\5', s)
다음 솔루션은 Python 2.7.x에서 올바르게 동작하는 것 같습니다.Python 2.7의 Custom JSON 인코더에서 가져온 회피책을 사용하여 플레인 JavaScript 코드를 삽입하여 UUID 기반 대체 방식을 사용하여 커스텀 인코딩된 개체가 출력에서 JSON 문자열로 끝나는 것을 방지합니다.
class NoIndent(object):
def __init__(self, value):
self.value = value
class NoIndentEncoder(json.JSONEncoder):
def __init__(self, *args, **kwargs):
super(NoIndentEncoder, self).__init__(*args, **kwargs)
self.kwargs = dict(kwargs)
del self.kwargs['indent']
self._replacement_map = {}
def default(self, o):
if isinstance(o, NoIndent):
key = uuid.uuid4().hex
self._replacement_map[key] = json.dumps(o.value, **self.kwargs)
return "@@%s@@" % (key,)
else:
return super(NoIndentEncoder, self).default(o)
def encode(self, o):
result = super(NoIndentEncoder, self).encode(o)
for k, v in self._replacement_map.iteritems():
result = result.replace('"@@%s@@"' % (k,), v)
return result
그럼 이거
obj = {
"layer1": {
"layer2": {
"layer3_2": "string",
"layer3_1": NoIndent([{"y": 7, "x": 1}, {"y": 4, "x": 0}, {"y": 3, "x": 5}, {"y": 9, "x": 6}])
}
}
}
print json.dumps(obj, indent=2, cls=NoIndentEncoder)
는 다음과 같은 출력을 생성합니다.
{
"layer1": {
"layer2": {
"layer3_2": "string",
"layer3_1": [{"y": 7, "x": 1}, {"y": 4, "x": 0}, {"y": 3, "x": 5}, {"y": 9, "x": 6}]
}
}
}
It also correctly passes all options (except 또한 모든 옵션을 올바르게 통과시킵니다(단,indent
e)sort_keys=True
중첩된 완 히 downjson.dumps
전화 주문 부서 부탁드립니다.
obj = {
"layer1": {
"layer2": {
"layer3_1": NoIndent([{"y": 7, "x": 1, }, {"y": 4, "x": 0}, {"y": 3, "x": 5, }, {"y": 9, "x": 6}]),
"layer3_2": "string",
}
}
}
print json.dumps(obj, indent=2, sort_keys=True, cls=NoIndentEncoder)
올바른 출력:
{
"layer1": {
"layer2": {
"layer3_1": [{"x": 1, "y": 7}, {"x": 0, "y": 4}, {"x": 5, "y": 3}, {"x": 6, "y": 9}],
"layer3_2": "string"
}
}
}
It can also be combined with e.g. 또한 다음과 같이 조합할 수 있습니다.collections.OrderedDict
:
obj = {
"layer1": {
"layer2": {
"layer3_2": "string",
"layer3_3": NoIndent(OrderedDict([("b", 1), ("a", 2)]))
}
}
}
print json.dumps(obj, indent=2, cls=NoIndentEncoder)
출력:
{
"layer1": {
"layer2": {
"layer3_3": {"b": 1, "a": 2},
"layer3_2": "string"
}
}
}
업데이트: Python 3에는 없습니다.iteritems
바꿀 수 encode
뭇매를 맞다
def encode(self, o):
result = super(NoIndentEncoder, self).encode(o)
for k, v in iter(self._replacement_map.items()):
result = result.replace('"@@%s@@"' % (k,), v)
return result
그러면 OP가 예상한 결과가 나타납니다.
import json
class MyJSONEncoder(json.JSONEncoder):
def iterencode(self, o, _one_shot=False):
list_lvl = 0
for s in super(MyJSONEncoder, self).iterencode(o, _one_shot=_one_shot):
if s.startswith('['):
list_lvl += 1
s = s.replace('\n', '').rstrip()
elif 0 < list_lvl:
s = s.replace('\n', '').rstrip()
if s and s[-1] == ',':
s = s[:-1] + self.item_separator
elif s and s[-1] == ':':
s = s[:-1] + self.key_separator
if s.endswith(']'):
list_lvl -= 1
yield s
o = {
"layer1":{
"layer2":{
"layer3_1":[{"y":7,"x":1},{"y":4,"x":0},{"y":3,"x":5},{"y":9,"x":6}],
"layer3_2":"string",
"layer3_3":["aaa\nbbb","ccc\nddd",{"aaa\nbbb":"ccc\nddd"}],
"layer3_4":"aaa\nbbb",
}
}
}
jsonstr = json.dumps(o, indent=2, separators=(',', ':'), sort_keys=True,
cls=MyJSONEncoder)
print(jsonstr)
o2 = json.loads(jsonstr)
print('identical objects: {}'.format((o == o2)))
다음을 시도해 보십시오.
말 것
NoIndentList
:class NoIndentList(list): pass
json을 덮어씁니다.Encoder.default 메서드를 사용하여 비인디트 문자열 표현을 생성합니다.
NoIndentList
.json.하면 json.dumps()를 호출할 수 .
indent
을
위의 접근방식은 json 모듈에서는 동작하지 않는 것 같습니다.
import json
import sys
class NoIndent(object):
def __init__(self, value):
self.value = value
def default(o, encoder=json.JSONEncoder()):
if isinstance(o, NoIndent):
return json.dumps(o.value)
return encoder.default(o)
L = [dict(x=x, y=y) for x in range(1) for y in range(2)]
obj = [NoIndent(L), L]
json.dump(obj, sys.stdout, default=default, indent=4)
유효하지 않은 출력이 생성됩니다(목록은 문자열로 시리얼화됩니다).
[
"[{\"y\": 0, \"x\": 0}, {\"y\": 1, \"x\": 0}]",
[
{
"y": 0,
"x": 0
},
{
"y": 1,
"x": 0
}
]
]
yaml
그 효과가 있습니다.
import sys
import yaml
class NoIndentList(list):
pass
def noindent_list_presenter(dumper, data):
return dumper.represent_sequence(u'tag:yaml.org,2002:seq', data,
flow_style=True)
yaml.add_representer(NoIndentList, noindent_list_presenter)
obj = [
[dict(x=x, y=y) for x in range(2) for y in range(1)],
[dict(x=x, y=y) for x in range(1) for y in range(2)],
]
obj[0] = NoIndentList(obj[0])
yaml.dump(obj, stream=sys.stdout, indent=4)
작성 방법:
- [{x: 0, y: 0}, {x: 1, y: 0}]
- - {x: 0, y: 0}
- {x: 0, y: 1}
첫 는 ,, 음, 음, 음, 첫, 첫, 첫, 화, 화, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i[]
모든 항목이 한 줄에 있고 두 번째 목록에는 항목당 한 줄이 사용됩니다.
JSON에 기여하는 개체 유형이 너무 많아 JSONncoder 메서드를 시도할 수 없는 경우 및 정규식을 사용할 수 없는 다양한 유형이 너무 많은 경우 후처리 솔루션이 있습니다.이 함수는 데이터 자체의 세부 사항을 알 필요 없이 지정된 수준 이후에 공백을 축소합니다.
def collapse_json(text, indent=12):
"""Compacts a string of json data by collapsing whitespace after the
specified indent level
NOTE: will not produce correct results when indent level is not a multiple
of the json indent level
"""
initial = " " * indent
out = [] # final json output
sublevel = [] # accumulation list for sublevel entries
pending = None # holder for consecutive entries at exact indent level
for line in text.splitlines():
if line.startswith(initial):
if line[indent] == " ":
# found a line indented further than the indent level, so add
# it to the sublevel list
if pending:
# the first item in the sublevel will be the pending item
# that was the previous line in the json
sublevel.append(pending)
pending = None
item = line.strip()
sublevel.append(item)
if item.endswith(","):
sublevel.append(" ")
elif sublevel:
# found a line at the exact indent level *and* we have sublevel
# items. This means the sublevel items have come to an end
sublevel.append(line.strip())
out.append("".join(sublevel))
sublevel = []
else:
# found a line at the exact indent level but no items indented
# further, so possibly start a new sub-level
if pending:
# if there is already a pending item, it means that
# consecutive entries in the json had the exact same
# indentation and that last pending item was not the start
# of a new sublevel.
out.append(pending)
pending = line.rstrip()
else:
if pending:
# it's possible that an item will be pending but not added to
# the output yet, so make sure it's not forgotten.
out.append(pending)
pending = None
if sublevel:
out.append("".join(sublevel))
out.append(line)
return "\n".join(out)
예를 들어, 이 구조를 들여쓰기 레벨이 4인 json.dumps에 대한 입력으로 사용합니다.
text = json.dumps({"zero": ["first", {"second": 2, "third": 3, "fourth": 4, "items": [[1,2,3,4], [5,6,7,8], 9, 10, [11, [12, [13, [14, 15]]]]]}]}, indent=4)
다음은 다양한 들여쓰기 수준에서의 함수 출력입니다.
>>> print collapse_json(text, indent=0)
{"zero": ["first", {"items": [[1, 2, 3, 4], [5, 6, 7, 8], 9, 10, [11, [12, [13, [14, 15]]]]], "second": 2, "fourth": 4, "third": 3}]}
>>> print collapse_json(text, indent=4)
{
"zero": ["first", {"items": [[1, 2, 3, 4], [5, 6, 7, 8], 9, 10, [11, [12, [13, [14, 15]]]]], "second": 2, "fourth": 4, "third": 3}]
}
>>> print collapse_json(text, indent=8)
{
"zero": [
"first",
{"items": [[1, 2, 3, 4], [5, 6, 7, 8], 9, 10, [11, [12, [13, [14, 15]]]]], "second": 2, "fourth": 4, "third": 3}
]
}
>>> print collapse_json(text, indent=12)
{
"zero": [
"first",
{
"items": [[1, 2, 3, 4], [5, 6, 7, 8], 9, 10, [11, [12, [13, [14, 15]]]]],
"second": 2,
"fourth": 4,
"third": 3
}
]
}
>>> print collapse_json(text, indent=16)
{
"zero": [
"first",
{
"items": [
[1, 2, 3, 4],
[5, 6, 7, 8],
9,
10,
[11, [12, [13, [14, 15]]]]
],
"second": 2,
"fourth": 4,
"third": 3
}
]
}
베스트 퍼포먼스 코드(10MB 텍스트 비용 1s):
import json
def dumps_json(data, indent=2, depth=2):
assert depth > 0
space = ' '*indent
s = json.dumps(data, indent=indent)
lines = s.splitlines()
N = len(lines)
# determine which lines to be shortened
is_over_depth_line = lambda i: i in range(N) and lines[i].startswith(space*(depth+1))
is_open_bracket_line = lambda i: not is_over_depth_line(i) and is_over_depth_line(i+1)
is_close_bracket_line = lambda i: not is_over_depth_line(i) and is_over_depth_line(i-1)
#
def shorten_line(line_index):
if not is_open_bracket_line(line_index):
return lines[line_index]
# shorten over-depth lines
start = line_index
end = start
while not is_close_bracket_line(end):
end += 1
has_trailing_comma = lines[end][-1] == ','
_lines = [lines[start][-1], *lines[start+1:end], lines[end].replace(',','')]
d = json.dumps(json.loads(' '.join(_lines)))
return lines[line_index][:-1] + d + (',' if has_trailing_comma else '')
#
s = '\n'.join([
shorten_line(i)
for i in range(N) if not is_over_depth_line(i) and not is_close_bracket_line(i)
])
#
return s
업데이트: 설명하겠습니다.
먼저 json.dumps를 사용하여 json 문자열을 들여씁니다.예:
>>> print(json.dumps({'0':{'1a':{'2a':None,'2b':None},'1b':{'2':None}}}, indent=2))
[0] {
[1] "0": {
[2] "1a": {
[3] "2a": null,
[4] "2b": null
[5] },
[6] "1b": {
[7] "2": null
[8] }
[9] }
[10] }
「 」를 indent=2
★★★★★★★★★★★★★★★★★」depth = 2
은 6개의 6개의 공백으로 시작합니다.
라인에는 4종류가 있습니다.
- 노멀 라인
- 열린 브래킷 라인(2,6)
- 깊이선 초과(3,4,7)
- 브래킷 라인 닫기(5,8)
일련의 라인(타입 2 + 3 + 4)을 1개의 라인으로 결합합니다.예:
[2] "1a": {
[3] "2a": null,
[4] "2b": null
[5] },
다음과 같이 통합됩니다.
[2] "1a": {"2a": null, "2b": null},
메모: 괄호 닫기 행에는 쉼표가 있을 수 있습니다.
나와 Python 3 사용자에 대한 답변
import re
def jsonIndentLimit(jsonString, indent, limit):
regexPattern = re.compile(f'\n({indent}){{{limit}}}(({indent})+|(?=(}}|])))')
return regexPattern.sub('', jsonString)
if __name__ == '__main__':
jsonString = '''{
"layer1": {
"layer2": {
"layer3_1": [
{
"x": 1,
"y": 7
},
{
"x": 0,
"y": 4
},
{
"x": 5,
"y": 3
},
{
"x": 6,
"y": 9
}
],
"layer3_2": "string"
}
}
}'''
print(jsonIndentLimit(jsonString, ' ', 3))
'''print
{
"layer1": {
"layer2": {
"layer3_1": [{"x": 1,"y": 7},{"x": 0,"y": 4},{"x": 5,"y": 3},{"x": 6,"y": 9}],
"layer3_2": "string"
}
}
}'''
이 솔루션은 다른 솔루션보다 우아하고 일반적이지 않으며 많은 것을 배울 수는 없지만 빠르고 단순합니다.
def custom_print(data_structure, indent):
for key, value in data_structure.items():
print "\n%s%s:" % (' '*indent,str(key)),
if isinstance(value, dict):
custom_print(value, indent+1)
else:
print "%s" % (str(value)),
사용방법 및 출력:
>>> custom_print(data_structure,1)
layer1:
layer2:
layer3_2: string
layer3_1: [{'y': 7, 'x': 1}, {'y': 4, 'x': 0}, {'y': 3, 'x': 5}, {'y': 9, 'x': 6}]
참고로 이 웹사이트에는 내장된 JavaScript가 있어 행이 70자 미만일 때 JSON 문자열로 행 피드를 회피합니다.
http://www.csvjson.com/json_beautifier
(JSON-js의 수정 버전을 사용하여 구현되었습니다.)
인라인 쇼트 어레이를 선택합니다.
복사 버퍼에 있는 데이터를 빠르게 볼 수 있습니다.
역시 YAML이 JSON보다 더 좋은 것 중 하나입니다.
NoIndentEncoder를 사용할 수 없지만 JSON 문자열에서 regex를 사용할 수 있습니다.
def collapse_json(text, list_length=5):
for length in range(list_length):
re_pattern = r'\[' + (r'\s*(.+)\s*,' * length)[:-1] + r'\]'
re_repl = r'[' + ''.join(r'\{}, '.format(i+1) for i in range(length))[:-2] + r']'
text = re.sub(re_pattern, re_repl, text)
return text
문제는 중첩된 목록에서 이 작업을 어떻게 수행하느냐입니다.
이전:
[
0,
"any",
[
2,
3
]
]
그 후:
[0, "any", [2, 3]]
언급URL : https://stackoverflow.com/questions/13249415/how-to-implement-custom-indentation-when-pretty-printing-with-the-json-module
'programing' 카테고리의 다른 글
React에서 하위 구성 요소 동적 추가 (0) | 2023.03.17 |
---|---|
Angularjs $http 및 진행률 바 (0) | 2023.03.17 |
jQuery AJAX 오류 처리(HTTP 상태 코드) (0) | 2023.03.17 |
모든 도메인에 대해 문서 루트 외부에 CMS 설치 가능 (0) | 2023.03.17 |
WooCommerce 훅은 "결제 완료 후" 액션에 사용됩니다. (0) | 2023.03.17 |