gpt4 book ai didi

python - 在一行中格式化某些 JSON 对象

转载 作者:太空狗 更新时间:2023-10-30 01:20:23 25 4
gpt4 key购买 nike

考虑以下代码:

>>> import json
>>> data = {
... 'x': [1, {'$special': 'a'}, 2],
... 'y': {'$special': 'b'},
... 'z': {'p': True, 'q': False}
... }
>>> print(json.dumps(data, indent=2))
{
"y": {
"$special": "b"
},
"z": {
"q": false,
"p": true
},
"x": [
1,
{
"$special": "a"
},
2
]
}

我想要的是格式化 JSON,以便只有一个属性 '$special' 的 JSON 对象呈现在一行上,如下所示。

{
"y": {"$special": "b"},
"z": {
"q": false,
"p": true
},
"x": [
1,
{"$special": "a"},
2
]
}

我尝试过实现自定义 JSONEncoder并将其作为 cls 参数传递给 json.dumps,但是 JSONEncoder 上的两种方法各有一个问题:

  • JSONEncoder defaultdata 的每个部分调用方法,但返回值不是原始 JSON 字符串,因此似乎没有任何方法可以调整其格式。

  • JSONEncoder encode方法确实会返回原始 JSON 字符串,但对于整个 data 只调用一次。

有什么方法可以让 JSONEncoder 做我想做的事吗?

最佳答案

json 模块的设计并不是为了让您对输出有那么多的控制;缩进主要是为了在调试时提高可读性。

不是让 json 产生输出,您可以使用标准库转换输出 tokenize module :

import tokenize
from io import BytesIO


def inline_special(json_data):
def adjust(t, ld,):
"""Adjust token line number by offset"""
(sl, sc), (el, ec) = t.start, t.end
return t._replace(start=(sl + ld, sc), end=(el + ld, ec))

def transform():
with BytesIO(json_data.encode('utf8')) as b:
held = [] # to defer newline tokens
lastend = None # to track the end pos of the prev token
loffset = 0 # line offset to adjust tokens by
tokens = tokenize.tokenize(b.readline)
for tok in tokens:
if tok.type == tokenize.NL:
# hold newlines until we know there's no special key coming
held.append(adjust(tok, loffset))
elif (tok.type == tokenize.STRING and
tok.string == '"$special"'):
# special string, collate tokens until the next rbrace
# held newlines are discarded, adjust the line offset
loffset -= len(held)
held = []
text = [tok.string]
while tok.exact_type != tokenize.RBRACE:
tok = next(tokens)
if tok.type != tokenize.NL:
text.append(tok.string)
if tok.string in ':,':
text.append(' ')
else:
loffset -= 1 # following lines all shift
line, col = lastend
text = ''.join(text)
endcol = col + len(text)
yield tokenize.TokenInfo(
tokenize.STRING, text, (line, col), (line, endcol),
'')
# adjust any remaining tokens on this line
while tok.type != tokenize.NL:
tok = next(tokens)
yield tok._replace(
start=(line, endcol),
end=(line, endcol + len(tok.string)))
endcol += len(tok.string)
else:
# uninteresting token, yield any held newlines
if held:
yield from held
held = []
# adjust and remember last position
tok = adjust(tok, loffset)
lastend = tok.end
yield tok

return tokenize.untokenize(transform()).decode('utf8')

这会成功地重新格式化您的样本:

import json

data = {
'x': [1, {'$special': 'a'}, 2],
'y': {'$special': 'b'},
'z': {'p': True, 'q': False}
}

>>> print(inline_special(json.dumps(data, indent=2)))
{
"x": [
1,
{"$special": "a"},
2
],
"y": {"$special": "b"},
"z": {
"p": true,
"q": false
}
}

关于python - 在一行中格式化某些 JSON 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40028755/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com