无法使用包含换行符的字符串从dict创建JSON doc

时间:2016-11-15 11:03:40

标签: python json dictionary linefeed

我正在创建一个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 }'

但是当我使用load来创建/编码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字符串中支持的字符。

这里究竟出现了什么问题以及如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

在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)

答案 1 :(得分:0)

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

/**
 * Checks given IP against array of masks like 123.123.123.123, 123.123.*.101, 123.123., 123.123.1*.*
 *
 * @param $ip
 * @param $masks
 * @return bool
 */
public static function checkIp($ip, $masks)
{
    if (in_array($ip, $masks)) {
        return true;  // Simple match
    } else {
        foreach ($masks as $mask) {
            if (substr($mask, -1) == '.' AND substr($ip, 0, strlen($mask)) == $mask) {
                return true; // Case for 123.123. mask
            }
            if (strpos($mask, '*') === false) {
                continue; // No simple matching and no wildcard in the mask, leaves no chance to match
            }
            // Breaking into triads
            $maskParts = explode('.', $mask);
            $ipParts = explode('.', $ip);
            foreach ($maskParts as $key => $maskPart) {
                if ($maskPart == '*') {
                    continue;  // This triad is matching, continue with next triad
                } elseif (strpos($maskPart, '*') !== false) {
                    // Case like 1*, 1*2, *1
                    // Let's use regexp for this
                    $regExp = str_replace('*', '\d{0,3}', $maskPart);
                    if (preg_match('/^' . $regExp . '$/', $ipParts[$key])) {
                        continue;  // Matching, go to check next triad
                    } else {
                        continue 2;  // Not matching, Go to check next mask
                    }
                } else {
                    if ($maskPart != $ipParts[$key]) {
                        continue 2; // If triad has no wildcard and not matching, check next mask
                    }
                    // otherwise just continue
                }
            }
            // We checked all triads and all matched, hence this mask is matching
            return true;
        }
        // We went through all masks and none has matched.
        return false;
    }
}

在dict python中加载字符串JSON:

import json
changes_str = json.dumps(changes)