显示比“无 JSON 对象可解码”更好的错误消息

Python 代码从一些长的复杂的 JSON 文件中加载数据:

with open(filename, "r") as f:
data = json.loads(f.read())

(注意: 最佳代码版本应该是:

with open(filename, "r") as f:
data = json.load(f)

但两者表现出相似的行为)

对于许多类型的 JSON 错误(缺少分隔符、字符串中不正确的反斜杠等) ,这将打印出一个非常有用的消息,其中包含发现 JSON 错误的行号和列号。

然而,对于其他类型的 JSON 错误(包括经典的“在列表中的最后一项使用逗号”,以及大写 true/false 等其他错误) ,Python 的输出只是:

Traceback (most recent call last):
File "myfile.py", line 8, in myfunction
config = json.loads(f.read())
File "c:\python27\lib\json\__init__.py", line 326, in loads
return _default_decoder.decode(s)
File "c:\python27\lib\json\decoder.py", line 360, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "c:\python27\lib\json\decoder.py", line 378, in raw_decode
raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

对于这种类型的 ValueError,如何让 Python 告诉您 JSON 文件中的错误位置?

319284 次浏览

您不能让 python 告诉您哪里的 JSON 不正确。您将需要在线使用类似于 这个的线程

这将显示您试图解码的 JSON 中的错误。

我发现 simplejson模块在许多内置 json模块不明确的情况下提供了更多的描述性错误。例如,对于列表中最后一项后面有逗号的情况:

json.loads('[1,2,]')
....
ValueError: No JSON object could be decoded

simplejson相同的操作:

simplejson.loads('[1,2,]')
...
simplejson.decoder.JSONDecodeError: Expecting object: line 1 column 5 (char 5)

好多了! 对于其他常见错误,如大写 True,也是如此。

您可以尝试在这里找到的 rson 库: http://code.google.com/p/rson/。我也把它放在 PYPI: https://pypi.python.org/pypi/rson/0.9上,因此您可以使用 easy _ install 或 pip 来获取它。

汤姆给出的例子:

>>> rson.loads('[1,2,]')
...
rson.base.tokenizer.RSONDecodeError: Unexpected trailing comma: line 1, column 6, text ']'

RSON 被设计成 JSON 的超集,因此它可以解析 JSON 文件。它还有另一种语法,很多更适合人们查看和编辑。我经常把它用于输入文件。

至于布尔值的大写: rson 将大写不正确的布尔值读作字符串。

>>> rson.loads('[true,False]')
[True, u'False']

您可以使用 Cjson,它声称比纯 Python 实现快250倍,因为您有“一些长而复杂的 JSON 文件”,并且您可能需要多次运行它(解码器失败并且只报告遇到的第一个错误)。

我也遇到过类似的问题,这是由于单引号引起的。JSON 标准(http://json.org)只谈到使用 双引号,因此 pythonjson库必须只支持双引号。

对于这个问题的特定版本,我继续在 packaging.py文件中搜索 load_json_file(path)的函数声明,然后在其中插入一行 print:

def load_json_file(path):
data = open(path, 'r').read()
print data
try:
return Bunch(json.loads(data))
except ValueError, e:
raise MalformedJsonFileError('%s when reading "%s"' % (str(e),
path))

这样,它就会在输入 try-catch 之前打印出 json 文件的内容,这样,即使我几乎没有 Python 方面的知识,我也能够很快地弄清楚为什么我的配置无法读取 json 文件。
(这是因为我设置了我的文本编辑器来编写 UTF-8 BOM... 愚蠢)

仅仅提到这一点是因为,虽然这可能不是 OP 特定问题的好答案,但是这是确定一个非常令人压抑的 bug 的来源的一个相当快速的方法。我敢打赌,许多人会偶然发现这篇文章谁正在寻找一个更详细的解决方案的 MalformedJsonFileError: No JSON object could be decoded when reading …。所以这可能对他们有帮助。

我也遇到过类似的问题,这就是我的代码:

    json_file=json.dumps(pyJson)
file = open("list.json",'w')
file.write(json_file)


json_file = open("list.json","r")
json_decoded = json.load(json_file)
print json_decoded

问题是我忘记了 file.close()我这样做,并修复了问题。

公认的答案是解决这个问题最容易的答案。但是,如果你不允许安装 simplejson 由于您的公司政策,我建议以下解决方案,以解决特定问题的 “在列表的最后一项使用逗号”:

  1. 创建一个子类“ JSONLintCheck”从类“ JSONDecder”继承,并覆盖类“ JSONDecder”的 Init方法,如下所示:

    def __init__(self, encoding=None, object_hook=None, parse_float=None,parse_int=None, parse_constant=None, strict=True,object_pairs_hook=None)
    super(JSONLintCheck,self).__init__(encoding=None, object_hook=None,      parse_float=None,parse_int=None, parse_constant=None, strict=True,object_pairs_hook=None)
    self.scan_once = make_scanner(self)
    
  1. make_scanner is a new function that used to override the 'scan_once' method of the above class. And here is code for it:
  1 #!/usr/bin/env python
2 from json import JSONDecoder
3 from json import decoder
4 import re
5
6 NUMBER_RE = re.compile(
7     r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?',
8     (re.VERBOSE | re.MULTILINE | re.DOTALL))
9
10 def py_make_scanner(context):
11     parse_object = context.parse_object
12     parse_array = context.parse_array
13     parse_string = context.parse_string
14     match_number = NUMBER_RE.match
15     encoding = context.encoding
16     strict = context.strict
17     parse_float = context.parse_float
18     parse_int = context.parse_int
19     parse_constant = context.parse_constant
20     object_hook = context.object_hook
21     object_pairs_hook = context.object_pairs_hook
22
23     def _scan_once(string, idx):
24         try:
25             nextchar = string[idx]
26         except IndexError:
27             raise ValueError(decoder.errmsg("Could not get the next character",string,idx))
28             #raise StopIteration
29
30         if nextchar == '"':
31             return parse_string(string, idx + 1, encoding, strict)
32         elif nextchar == '{':
33             return parse_object((string, idx + 1), encoding, strict,
34                 _scan_once, object_hook, object_pairs_hook)
35         elif nextchar == '[':
36             return parse_array((string, idx + 1), _scan_once)
37         elif nextchar == 'n' and string[idx:idx + 4] == 'null':
38             return None, idx + 4
39         elif nextchar == 't' and string[idx:idx + 4] == 'true':
40             return True, idx + 4
41         elif nextchar == 'f' and string[idx:idx + 5] == 'false':
42             return False, idx + 5
43
44         m = match_number(string, idx)
45         if m is not None:
46             integer, frac, exp = m.groups()
47             if frac or exp:
48                 res = parse_float(integer + (frac or '') + (exp or ''))
49             else:
50                 res = parse_int(integer)
51             return res, m.end()
52         elif nextchar == 'N' and string[idx:idx + 3] == 'NaN':
53             return parse_constant('NaN'), idx + 3
54         elif nextchar == 'I' and string[idx:idx + 8] == 'Infinity':
55             return parse_constant('Infinity'), idx + 8
56         elif nextchar == '-' and string[idx:idx + 9] == '-Infinity':
57             return parse_constant('-Infinity'), idx + 9
58         else:
59             #raise StopIteration   # Here is where needs modification
60             raise ValueError(decoder.errmsg("Expecting propert name enclosed in double quotes",string,idx))
61     return _scan_once
62
63 make_scanner = py_make_scanner
  1. 最好将‘ make _ scanner’函数和新的子类放在同一个文件中。

对我来说,我的 json 文件非常大,当在 python 中使用常见的 json时,它会得到上面的错误。

通过 sudo pip install simplejson安装 simplejson后。

然后我解决了。

import json
import simplejson




def test_parse_json():
f_path = '/home/hello/_data.json'
with open(f_path) as f:
# j_data = json.load(f)      # ValueError: No JSON object could be decoded
j_data = simplejson.load(f)  # right
lst_img = j_data['images']['image']
print lst_img[0]




if __name__ == '__main__':
test_parse_json()

只是碰到了相同的问题,在我的情况下,问题与文件开头的 BOM(字节顺序标记)有关。

json.tool甚至会拒绝处理空文件(只是大括号) ,直到我删除了 UTF BOM 标记。

我所做的是:

  • 用 Vim 打开我的 json 文件,
  • 删除的字节顺序标记(set nobomb)
  • 保存文件

这解决了 json.tool 的问题,希望对您有所帮助!

创建文件时,不要创建内容为空的文件。替换为:

json.dump({}, file)