10

当我在 Python 3 中使用 json.loads 并捕获任何由此产生的错误时,例如:

try:
  data = json.loads(string)
except ValueError as err:
  print(err)

我收到一条有用的消息,例如:

Expecting ',' delimiter: line 12 column 12 (char 271)

我希望能够向用户显示它,以及导致问题的确切位置(我正在阅读用户编写的 JSON)。我怎样才能摆脱线和列?

我可以在 err 上使用正则表达式,但这感觉是个坏主意,因为我不知道这条消息是否已国际化,并且可能会在不同版本的 python 中发生变化。有没有更好的办法?

4

3 回答 3

9

扫描json/decoder.py 源码,我们可以看到解码器的错误信息是使用errmsg函数构造的:

def errmsg(msg, doc, pos, end=None):
    # Note that this function is called from _json
    lineno, colno = linecol(doc, pos)
    if end is None:
        fmt = '{0}: line {1} column {2} (char {3})'
        return fmt.format(msg, lineno, colno, pos)
        #fmt = '%s: line %d column %d (char %d)'
        #return fmt % (msg, lineno, colno, pos)
    endlineno, endcolno = linecol(doc, end)
    fmt = '{0}: line {1} column {2} - line {3} column {4} (char {5} - {6})'
    return fmt.format(msg, lineno, colno, endlineno, endcolno, pos, end)
    #fmt = '%s: line %d column %d - line %d column %d (char %d - %d)'
    #return fmt % (msg, lineno, colno, endlineno, endcolno, pos, end)

由于这是一个纯 Python 模块,因此很容易用自定义函数包装这个函数。这个过程被称为猴子补丁

import json

original_errmsg= json.decoder.errmsg

def our_errmsg(msg, doc, pos, end=None):
    json.last_error_position= json.decoder.linecol(doc, pos)
    return original_errmsg(msg, doc, pos, end)

json.decoder.errmsg= our_errmsg

try:
    data = json.loads('{1:}')
except ValueError as e:
    print("error at", json.last_error_position)

显然,这种解决方案并不理想,因为实现可能随时发生变化,尽管它仍然比依赖消息要好。您应该在修补之前检查是否errmsg存在(并且可能如果没有其他参数,或者使用可变参数)。

于 2013-10-22T14:25:49.233 回答
5

如果你使用simplejson库,你会得到一个合格的JSONDecodeError

class JSONDecodeError(ValueError):
   """Subclass of ValueError with the following additional properties:

   msg: The unformatted error message
   doc: The JSON document being parsed
   pos: The start index of doc where parsing failed
   end: The end index of doc where parsing failed (may be None)
   lineno: The line corresponding to pos
   colno: The column corresponding to pos
   endlineno: The line corresponding to end (may be None)
   endcolno: The column corresponding to end (may be None)

   """

希望这将很快合并到 stdlib中。

于 2013-10-23T14:10:13.450 回答
1

如果 json 对象很小,请在此处 http://jsonlint.com/过去您的 Json 对象, 它会给出 json 中断的位置。

于 2013-10-23T10:15:54.463 回答