漂亮的打印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的主要内容,如果未能解决你的问题,请参考以下文章