考虑以下代码:

>>> 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 并将其作为json.dumps参数传递给cls的方法,但是JSONEncoder上的两个方法都有一个问题:
  • JSONEncoder的每个部分调用default data 方法,但是返回值不是原始的JSON字符串,因此似乎没有任何方法可以调整其格式。
  • JSONEncoder encode 方法的确返回原始JSON字符串,但整个data仅被调用一次。

  • 有什么办法可以让JSONEncoder做我想做的事情?

    最佳答案

    json模块并不是真正为您提供对输出的太多控制;缩进主要是为了在调试时提高可读性。

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

    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/

    10-17 00:27