无法使用包含换行字符的字符串从字典创建 JSON 文档

Can't create JSON doc from dict with string containing line feed chars

我正在创建一个 JSON 结构,我最终需要将其保存到一个文件中,但我遇到了嵌入换行符的问题。

我先创建字典:

changes = {
   "20161101": "Added logging",
    "20161027": "Fixed scrolling bug",
    "20161024": "Added summary functionality"
}

然后将其转换为单个换行符分隔的字符串:

changes_str = '\n'.join([ "{0} - {1}".format(x, y) for x, y in changes.items() ])
print changes_str
'20161101 - Added logging\n20161027 - Fixed scrolling bug\n20161024 - Added summary functionality'

到目前为止,还不错。现在我将它添加到字符串中(实际上它来自文本模板):

changes_str_json_str = '{ "version": 1.1, "changes": "' + changes_str + '" }'
print changes_str_json_str
'{ "version": 1.1, "changes": 20161101 - Added logging\n20161027 - Fixed scrolling bug\n20161024 - Added summary functionality }'

但是当我使用负载从中创建/编码一个 JSON 对象时,我遇到了问题:

json_obj = json.loads(changes_str_json_str)

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/python2.7/json/__init__.py", line 339, in loads
    return _default_decoder.decode(s)
  File "/opt/python2.7/json/decoder.py", line 364, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/opt/python2.7/json/decoder.py", line 380, in raw_decode
    obj, end = self.scan_once(s, idx)
ValueError: Invalid control character at: line 1 column 55 (char 54)

将换行更改为另一个字符确实解决了问题,所以很明显这就是问题所在,但是,我确实需要将字符作为换行符,因为最终文件中的数据需要像这样格式化(该文件被传递到另一个我无法控制的系统。另外,据我所知,换行符是 JSON 字符串中受支持的字符。

这里到底是什么问题,我该如何解决?

将其转换为单个换行符分隔的字符串:

import json
changes_str = json.dumps(changes)

在字典 python 中加载字符串 JSON:

dict_changes = json.loads(changes_str)

在JSON中你需要正确转义包括\n在内的控制字符。以下是当前正在发生的事情的示例:

>>> import json
>>> json.loads('"foo\nbar"')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\python35\lib\json\__init__.py", line 319, in loads
    return _default_decoder.decode(s)
  File "C:\python35\lib\json\decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "C:\python35\lib\json\decoder.py", line 355, in raw_decode
    obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Invalid control character at: line 1 column 5 (char 4)

如果您使用反斜杠正确转义换行符,它将按预期工作:

>>> json.loads('"foo\nbar"')
'foo\nbar'

因此您可以通过执行以下操作来修复您的代码:

changes_str = '\n'.join([ "{0} - {1}".format(x, y) for x, y in changes.items() ])

更好的选择是先构造您要输出的对象,然后使用 dumps 这样您就完全不用担心转义了:

obj = {
    'version': 1.1,
    'changes': changes_str
}
changes_str_json_str = json.dumps(obj)