2013-10-22 14 views
9

Quando uso json.loads in Python 3 e raccogliere eventuali errori risultanti, come:Come ottenere posizione dell'errore da json.loads in Python

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

ricevo un messaggio utile come:

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

Vorrei essere in grado di visualizzarlo all'utente, insieme esattamente alla posizione che causa il problema (sto leggendo in JSON scritto dall'utente). Come posso uscire dalla linea e dalla colonna?

Potrei usare una regex su err, ma mi sembra una cattiva idea, dato che non so se questo messaggio è internazionalizzato, e potrebbe cambiare in diverse versioni di python. C'è un modo migliore?

risposta

8

Scansione del json/decoder.py source code, possiamo vedere che i messaggi di errore del decoder sono costruiti utilizzando la funzione 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) 

Poiché si tratta di un modulo di puro-python, è facile da avvolgere questa funzione con uno personalizzato. Questo processo è noto come monkey patching:

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) 

Ovviamente, questa soluzione non è l'ideale, dal momento che l'attuazione può cambiare in qualsiasi momento, anche se è sempre meglio che fare affidamento sul messaggio. È necessario verificare se esiste errmsg prima dell'aggiornamento (e possibilmente se non ci sono altri argomenti o utilizzare vararg).

+0

Questo è molto interessante, ma penso che preferirei regexare la stringa, dato che posso sempre fare qualcos'altro se la mia regex non riesce a corrispondere in una versione futura, ma questo potrebbe (mi sembra) portare ad alcuni effetti collaterali davvero orribili. Tuttavia, questo continua a rispondere alla domanda come "no" e mi consente anche di cercare tutti i formati di messaggio che potrei restituire. Grazie! –

+0

Penso che sarebbe più bello se il parser JSON restituisse un'eccezione più qualificata che contiene questi campi. Ho aperto un [problema] (http://bugs.python.org/issue19361) per questo. –

0

se json oggetto è piccolo, Passato il tuo oggetto Json qui http://jsonlint.com/ dà dove json rompe.

+1

Voglio usare questo in un programma, mentre quel sito Web è utile Non vorrei iniziare a chiamarlo nel mio codice! –

3

Se si utilizza simplejson biblioteca, si ottiene un ben qualificato 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) 

    """ 

Speriamo che questo sarà merged into stdlib presto.

Problemi correlati