Comment vérifier si une chaîne est un JSON valide en Python?

184

En Python, existe-t-il un moyen de vérifier si une chaîne est JSON valide avant d'essayer de l'analyser?

Par exemple, en travaillant avec des choses comme l'API Facebook Graph, parfois il renvoie JSON, parfois il peut renvoyer un fichier image.

Joey Blake
la source
3
l'API devrait définir le type de contenu
John La Rooy
4
Vous ne pouvez pas spécifier quelles données sont renvoyées dans l'appel d'API? Je ne suis pas familier avec l'API Facebook, mais cela semble vraiment étrange.
jhocking le
Je l'ai fait une fois, mais avec codegolf way
VOUS
1
La plupart des réponses sont json, mais si vous appelez la photo de profil, elle renvoie simplement le jpg
Joey Blake

Réponses:

235

Vous pouvez essayer de faire json.loads(), ce qui jettera unValueError si la chaîne que vous passez ne peut pas être décodée en JSON.

En général, la philosophie « pythonique » pour ce genre de situation est appelée EAFP , pour plus facile de demander pardon que la permission .

John Flatness
la source
4
Je peux voir comment cela fonctionnera. M'amène à ma prochaine question. Il lance une ValueError. Ce que je veux faire à ce stade est de renvoyer la chaîne incriminée afin que je puisse faire autre chose avec elle. Jusqu'à présent, je n'ai reçu que le message d'erreur et le type.
Joey Blake
2
Quel est le problème avec le simple retour de la chaîne que vous avez passée loadsdans la clause except?
John Flatness
1
rien de mal à cela, juste une erreur noob de ma part. Il semble que je ne peux pas appeler file.read () deux fois. Mais je peux définir une variable et l'utiliser. Et c'est ce que j'ai fait.
Joey Blake le
5
juste une note ... json.loads ('10 ') ne lance pas ValueError et je suis sûr que' 10 'n'est pas un json valide ...
wahrheit
4
Malgré le fait que la spécification indique qu'un texte JSON doit être un tableau ou un objet, la plupart des encodeurs et décodeurs (y compris ceux de Python) fonctionneront avec n'importe quelle valeur JSON en «haut», y compris les nombres et les chaînes. 10est une valeur numérique JSON valide.
John Flatness
145

Exemple de script Python renvoie un booléen si une chaîne est valide json:

import json

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

Quelles impressions:

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

Convertissez une chaîne JSON en dictionnaire Python:

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

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

Convertissez un objet python en chaîne JSON:

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

Si vous souhaitez accéder à l'analyse de bas niveau, ne lancez pas la vôtre, utilisez une bibliothèque existante: http://www.json.org/

Excellent tutoriel sur le module JSON python: https://pymotw.com/2/json/

Est String JSON et affiche les erreurs de syntaxe et les messages d'erreur:

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

Impressions:

, 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 est capable de vérifier la syntaxe, d'analyser, de prittifier, d'encoder, de décoder et plus encore:

https://metacpan.org/pod/json_xs

Eric Leschinski
la source
Pensez-vous que nous devrions del json_objectune fois validé?
Akshay
4
Pourquoi diable n'y a-t-il pas de méthode de validation appropriée? Il devrait y avoir un moyen de vérifier les erreurs sans tuer les canaris.
Braden Best
Ce à quoi je veux en venir, c'est que ce n'est pas parce que Python autorise OO que vous pouvez ignorer les autres parties. Je devrais avoir l'option soit A. de laisser la fonction échouer et d'utiliser des exceptions (la manière OO / Python), ou B. d'appeler une fonction qui retourne une valeur (succès ou erreur) au lieu de lancer une exception, puis d'avoir ma fonction , à son tour, retourne une valeur sentinelle qui indique une erreur, de sorte que les erreurs remontent dans la pile d'appels et puissent être utilisées si nécessaire (méthode procédurale / C). Tout comme C ++ ne vous oblige pas à utiliser des exceptions (vous pouvez utiliser errno), Python ne devrait pas non plus le forcer
Braden Best
La validation de la chaîne JSON @BradenBest est hantée par le démon qui rend le problème d'arrêt intéressant. Il n'y a pas de moyen mathématiquement correct de prouver l'exactitude d'une chaîne, sauf pour essayer votre chaîne avec un analyseur et voir si elle se termine sans erreur. Pour voir pourquoi c'est difficile: "Ecrivez-moi un programme qui prouve qu'aucune erreur de syntaxe n'existe dans un programme informatique". Ce n'est pas possible. Les développeurs de langage seront poétiques sur l'éternelle course aux armements de l'encodage et du décodage. Le mieux que nous puissions faire est de retourner oui / non si une chaîne est valide pour un moteur donné, pas pour tous les moteurs possibles.
Eric Leschinski
1
@EricLeschinski mais il n'y a pas de problème d'arrêt ici. Le programme lève clairement une exception si une erreur se produit lors de l'analyse de JSON. Par conséquent, le programme sait quand l'entrée JSON est invalide. Par conséquent, il est possible à 100% d'avoir une fonction qui vérifie si l'entrée est valide sans avoir à l'utiliser try. #StopCanaryAbuse
Braden Best
2

Je dirais que l'analyse est la seule façon dont vous pouvez vraiment le dire. L'exception sera levée par pythonjson.loads() fonction (presque certainement) si ce n'est pas le format correct. Cependant, aux fins de votre exemple, vous pouvez probablement simplement vérifier les deux premiers caractères non blancs ...

Je ne connais pas le JSON que Facebook renvoie, mais la plupart des chaînes JSON des applications Web commenceront par un carré ouvert [ou bouclé{ crochet . Aucun format d'image que je connais ne commence par ces personnages.

Inversement, si vous savez quels formats d'image peuvent apparaître, vous pouvez vérifier le début de la chaîne pour leurs signatures pour identifier les images, et supposer que vous avez JSON si ce n'est pas une image.

Un autre hack simple pour identifier un graphique, plutôt qu'une chaîne de texte, dans le cas où vous recherchez un graphique, consiste simplement à tester les caractères non ASCII dans les deux premières douzaines de caractères de la chaîne (en supposant que le JSON est ASCII ).

Tim
la source
0

J'ai trouvé une solution générique et intéressante à ce problème:

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

et vous pouvez l'utiliser comme ceci:

safe_json = SafeInvocator(json)
text = "{'foo':'bar'}"
item = safe_json.loads(text)
if item:
    # do something
Odedlaz
la source
1
Je pense que les solutions générales sont bonnes, mais dans ce cas, la exceptclause peut cacher toute exception sérieuse. Les exceptions doivent être aussi restrictives que possible.
lucastamoios