Come posso verificare se una stringa è JSON valida in Python?


184

In Python, c'è un modo per verificare se una stringa è JSON valida prima di provare ad analizzarla?

Ad esempio, lavorando con cose come l'API Graph di Facebook, a volte restituisce JSON, a volte potrebbe restituire un file di immagine.


3
l'API dovrebbe impostare il tipo di contenuto
John La Rooy

4
Non è possibile specificare quali dati vengono restituiti nella chiamata API? Non ho familiarità con l'API di Facebook, ma sembra davvero strano.
jhocking

L'ho fatto una volta, ma con codegolf way
YOU

1
La maggior parte delle risposte sono json, ma se chiami la foto del profilo restituisce solo il jpg
Joey Blake

Risposte:


235

Puoi provare a farlo json.loads(), il che genererà un ValueErrorse la stringa che passi non può essere decodificata come JSON.

In generale, la filosofia " Pythonic " per questo tipo di situazione si chiama EAFP , perché è più facile chiedere perdono che autorizzazione .


4
Vedo come funzionerà. Mi porta alla mia prossima domanda. Genera un ValueError. Quello che voglio che faccia a questo punto è restituire la stringa offensiva in modo che io possa farci qualcos'altro. Finora ho ricevuto solo il messaggio di errore e il tipo.
Joey Blake,

2
Cosa c'è di sbagliato nel restituire la stringa a cui sei passato loadsnella clausola tranne?
John Flatness,

1
niente di sbagliato, solo un errore noob da parte mia. Sembra che non riesco a chiamare due volte file.read (). Ma posso impostare una variabile e usarla. Ed è quello che ho fatto.
Joey Blake,

5
solo una nota ... json.loads ('10 ') non genera ValueError e sono sicuro che' 10 'non è un json valido ...
wahrheit,

4
Nonostante il fatto che le specifiche affermino che un testo JSON deve essere un array o un oggetto, la maggior parte dei codificatori e decodificatori (compresi quelli di Python) funzionerà con qualsiasi valore JSON nella parte superiore, inclusi numeri e stringhe. 10è un valore numerico JSON valido.
John Flatness,

145

Lo script Python di esempio restituisce un valore booleano se una stringa è json valida:

import json

def is_json(myjson):
  try:
    json_object = json.loads(myjson)
  except ValueError as e:
    return False
  return True

Che stampa:

print is_json("{}")                          #prints True
print is_json("{asdf}")                      #prints False
print is_json('{ "age":100}')                #prints True
print is_json("{'age':100 }")                #prints False
print is_json("{\"age\":100 }")              #prints True
print is_json('{"age":100 }')                #prints True
print is_json('{"foo":[5,6.8],"foo":"bar"}') #prints True

Convertire una stringa JSON in un dizionario Python:

import json
mydict = json.loads('{"foo":"bar"}')
print(mydict['foo'])    #prints bar

mylist = json.loads("[5,6,7]")
print(mylist)
[5, 6, 7]

Convertire un oggetto Python in stringa JSON:

foo = {}
foo['gummy'] = 'bear'
print(json.dumps(foo))           #prints {"gummy": "bear"}

Se si desidera accedere all'analisi di basso livello, non creare il proprio, utilizzare una libreria esistente: http://www.json.org/

Grande tutorial sul modulo PSON JSON: https://pymotw.com/2/json/

Stringa JSON e mostra errori di sintassi e messaggi di errore:

sudo cpan JSON::XS
echo '{"foo":[5,6.8],"foo":"bar" bar}' > myjson.json
json_xs -t none < myjson.json

stampe:

, or } expected while parsing object/hash, at character offset 28 (before "bar}
at /usr/local/bin/json_xs line 183, <STDIN> line 1.

json_xs è in grado di verificare la sintassi, analizzare, eseguire la codifica, codificare, decodificare e altro:

https://metacpan.org/pod/json_xs


Pensi che dovremmo del json_objectconvalidare una volta?
Akshay,

4
Perché diavolo non esiste un metodo di validazione adeguato? Dovrebbe esserci un modo per controllare gli errori senza uccidere i canarini.
Braden Best,

Quello che sto ottenendo è: Solo perché Python consente OO non significa che va bene ignorare le altre parti. Dovrei avere l'opzione di A. lasciare che la funzione fallisca e usare le eccezioni (il modo OO / Python), oppure B. chiamare una funzione che ritorni un valore (successo o errore) invece di lanciare un'eccezione e quindi avere la mia funzione , a sua volta, restituisce un valore sentinella che indica un errore, in modo che gli errori riempiano lo stack di chiamate e possano essere utilizzati, se necessario (in modo procedurale / C). Proprio come C ++ non ti obbliga a usare le eccezioni (puoi usare errno), neanche Python dovrebbe forzarlo
Braden Best

La convalida della stringa JSON di @BradenBest è ossessionata dal demone che rende interessante il problema dell'arresto. Non esiste un modo matematicamente corretto per dimostrare la correttezza di una stringa se non quella di provare la stringa con un parser e vedere se termina senza errori. Per capire perché è difficile: "Scrivimi un programma che provi che non esistono errori di sintassi in un programma per computer". Non e possibile. Gli sviluppatori linguistici cercheranno poetica sull'eterna corsa agli armamenti di codifica e decodifica. Il meglio che possiamo fare è restituire sì / no se una stringa è valida per un determinato motore, non per tutti i motori possibili.
Eric Leschinski,

1
@EricLeschinski ma qui non c'è un problema di arresto. Il programma solleva chiaramente un'eccezione se si verifica un errore durante l'analisi di JSON. Pertanto, il programma sa quando l'input JSON non è valido. Pertanto, è possibile al 100% disporre di una funzione che controlla se l'input è valido senza la necessità di utilizzarlo try. #StopCanaryAbuse
Braden Best

2

Direi che analizzare è l'unico modo in cui puoi davvero dirlo interamente. L'eccezione sarà sollevata dalla json.loads()funzione di Python (quasi certamente) se non dal formato corretto. Tuttavia, per gli scopi del tuo esempio puoi probabilmente semplicemente controllare la prima coppia di caratteri non bianchi ...

Non ho familiarità con il JSON che Facebook restituisce, ma la maggior parte delle stringhe JSON delle app Web inizierà con una parentesi quadra [o riccia aperta {. Nessun formato di immagine che conosco inizia con quei personaggi.

Al contrario, se sai quali formati di immagine potrebbero essere visualizzati, puoi controllare l'inizio della stringa per le loro firme per identificare le immagini e assumere che tu abbia JSON se non è un'immagine.

Un altro semplice trucco per identificare un elemento grafico, anziché una stringa di testo, nel caso in cui tu stia cercando un elemento grafico, è solo testare caratteri non ASCII nella prima coppia di dozzine di caratteri della stringa (supponendo che JSON sia ASCII ).


0

Ho trovato una soluzione generica e interessante a questo problema:

class SafeInvocator(object):
    def __init__(self, module):
        self._module = module

    def _safe(self, func):
        def inner(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except:
                return None

        return inner

    def __getattr__(self, item):
        obj = getattr(self.module, item)
        return self._safe(obj) if hasattr(obj, '__call__') else obj

e puoi usarlo così:

safe_json = SafeInvocator(json)
text = "{'foo':'bar'}"
item = safe_json.loads(text)
if item:
    # do something

1
Penso che le soluzioni generali siano buone, ma in questo caso la exceptclausola può nascondere qualsiasi eccezione grave. La cattura delle eccezioni deve essere il più restrittiva possibile.
lucastamoios,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.