Displaying better error message than “No JSON object could be decoded”
从一些长而复杂的JSON文件加载数据的python代码:
1 2 | with open(filename,"r") as f: data = json.loads(f.read()) |
(注意:最好的代码版本应该是:
1 2 | with open(filename,"r") as f: data = json.load(f) |
号
但两者表现出相似的行为)
对于许多类型的JSON错误(缺少分隔符、字符串中不正确的反斜杠等),这将打印一条很好的有用消息,其中包含发现JSON错误的行号和列号。
但是,对于其他类型的JSON错误(包括经典的"在列表中的最后一个项目上使用逗号",以及其他类似大写"真/假"),python的输出只是:
1 2 3 4 5 6 7 8 9 10 | 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文件中的错误在哪里?
我发现,在许多情况下,
1 2 3 | json.loads('[1,2,]') .... ValueError: No JSON object could be decoded |
不是很有描述性。与
1 2 3 | simplejson.loads('[1,2,]') ... simplejson.decoder.JSONDecodeError: Expecting object: line 1 column 5 (char 5) |
好多了!同样,对于其他常见错误,如资本化
您将无法让Python告诉您JSON在哪里不正确。你需要在网上这样的地方使用一个线头。
这将显示您试图解码的JSON中的错误。
你可以试试这里的rson库:http://code.google.com/p/rson/。在pypi上也有:https://pypi.python.org/pypi/rson/0.9,这样您就可以使用easy-install或pip来获取它。
对于Tom给出的示例:
1 2 3 | >>> rson.loads('[1,2,]') ... rson.base.tokenizer.RSONDecodeError: Unexpected trailing comma: line 1, column 6, text ']' |
rson被设计成JSON的超集,因此它可以解析JSON文件。它还有另一种语法,对人类来说,这种语法更适合观察和编辑。我经常用它来输入文件。
至于布尔值的大写:似乎rson将错误大写的布尔值作为字符串读取。
1 2 | >>> rson.loads('[true,False]') [True, u'False'] |
我有一个类似的问题,这是由于单引号。JSON标准(http://json.org)只讨论使用双引号,所以必须是python
我也有类似的问题,这是我的代码:
1 2 3 4 5 6 7 | 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 |
问题是我忘了把问题交给埃多克斯,我做到了,解决了问题。
对于这个问题的具体版本,我在
1 2 3 4 5 6 7 8 | 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-8bom…太蠢了)
仅仅提到这一点是因为,虽然这可能不是一个很好的答案,但对于确定一个非常令人压抑的bug的来源来说,这是一个相当快速的方法。我敢打赌,许多人会偶然发现这篇文章,他们正在为
对于我来说,我的JSON文件非常大,在python中使用通用的
安装完
然后我就解决了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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() |
创建文件时。而不是创建内容为空的文件。替换为:
1 | json.dump({}, file) |
只是碰到了同样的问题,在我的例子中,这个问题与文件开头的EDOCX1(字节顺序标记)有关。
我所做的是:
- 用vim打开了我的json文件,
- 删除的字节顺序标记(
set nobomb ) - 保存文件
这就解决了json.tool的问题。希望这有帮助!
公认的答案是最容易解决问题的答案。但是,如果由于您的公司政策,您不能安装simplejson,我建议下面的解决方案来解决"在列表中的最后一项上使用逗号"的特定问题:
创建一个子类"jsonIntCheck"以从类"jsonDecoder"继承并重写类"jsonDecoder"的init方法,如下所示:
1 2 3 | 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 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 |
您可以使用cjson,它声称比纯python实现快250倍,因为您有"一些长期复杂的json文件",您可能需要多次运行它(解码器失败并报告它们遇到的第一个错误)。