Wie überprüfe ich, ob eine Zeichenfolge in Python JSON-gültig ist?

182

Gibt es in Python eine Möglichkeit, zu überprüfen, ob eine Zeichenfolge JSON-gültig ist, bevor Sie versuchen, sie zu analysieren?

Wenn Sie beispielsweise mit der Facebook Graph-API arbeiten, wird manchmal JSON zurückgegeben, manchmal wird eine Bilddatei zurückgegeben.

Joey Blake
quelle
3
Die API sollte den Inhaltstyp festlegen
John La Rooy
4
Sie können nicht angeben, welche Daten im API-Aufruf zurückgegeben werden. Ich bin nicht mit der Facebook-API vertraut, aber das klingt wirklich seltsam.
Jhocking
Ich habe einmal getan, aber mit codegolf Art und Weise
YOU
1
Die meisten Antworten sind json, aber wenn Sie das Profilfoto aufrufen, wird nur das jpg zurückgegeben
Joey Blake

Antworten:

231

Sie können versuchen, zu tun json.loads(), die ein werfen wirdValueError wenn die übergebene Zeichenfolge nicht als JSON dekodiert werden kann.

Im Allgemeinen wird die " pythonische " Philosophie für diese Art von Situation EAFP genannt , damit es einfacher ist, um Vergebung zu bitten als um Erlaubnis .

John Flatness
quelle
4
Ich kann sehen, wie das funktionieren wird. Führt mich zu meiner nächsten Frage. Es wird ein ValueError ausgelöst. An dieser Stelle soll die fehlerhafte Zeichenfolge zurückgegeben werden, damit ich etwas anderes damit tun kann. Bisher habe ich nur die Fehlermeldung und den Typ erhalten.
Joey Blake
2
Was ist falsch daran, nur die Zeichenfolge zurückzugeben, an die Sie loadsin der Except-Klausel übergeben haben?
John
1
Daran ist nichts auszusetzen, nur ein Fehler von meiner Seite. Es scheint, dass ich file.read () nicht zweimal aufrufen kann. Aber ich kann eine Variable setzen und verwenden. Und das habe ich getan.
Joey Blake
5
Nur eine Anmerkung ... json.loads ('10 ') löst den ValueError nicht aus und ich bin sicher, dass' 10 'kein gültiger json ist ...
wahrheit
4
Trotz der Tatsache, dass die Spezifikation besagt, dass ein JSON-Text ein Array oder Objekt sein muss, arbeiten die meisten Encoder und Decoder (einschließlich Pythons) mit jedem JSON-Wert oben, einschließlich Zahlen und Zeichenfolgen. 10ist ein gültiger JSON-Nummernwert.
John Flatness
144

Beispiel Ein Python-Skript gibt einen Booleschen Wert zurück, wenn eine Zeichenfolge gültig ist. Json:

import json

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

Welche Drucke:

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

Konvertieren Sie eine JSON-Zeichenfolge in ein Python-Wörterbuch:

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

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

Konvertieren Sie ein Python-Objekt in eine JSON-Zeichenfolge:

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

Wenn Sie auf Parsing auf niedriger Ebene zugreifen möchten, rollen Sie keine eigene, sondern verwenden Sie eine vorhandene Bibliothek: http://www.json.org/

Tolles Tutorial zum Python JSON-Modul: https://pymotw.com/2/json/

Ist String JSON und zeigt Syntaxfehler und Fehlermeldungen:

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

Drucke:

, 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 ist in der Lage, Syntax zu überprüfen, zu analysieren, zu analysieren, zu codieren, zu decodieren und vieles mehr:

https://metacpan.org/pod/json_xs

Eric Leschinski
quelle
Denken Sie, wir sollten del json_objecteinmal validiert werden?
Akshay
4
Warum zum Teufel gibt es keine richtige Validierungsmethode? Es sollte eine Möglichkeit geben, Fehler zu überprüfen, ohne Kanarienvögel zu töten.
Braden Best
Worauf ich hinaus will, ist: Nur weil Python OO zulässt, heißt das nicht, dass es in Ordnung ist, die anderen Teile zu ignorieren. Ich sollte die Option haben, entweder A. die Funktion fehlschlagen zu lassen und Ausnahmen zu verwenden (OO / Python-Methode), oder B. eine Funktion aufzurufen, die einen Wert (Erfolg oder Fehler) zurückgibt, anstatt eine Ausnahme auszulösen, und dann meine Funktion zu haben Geben Sie wiederum einen Sentinel-Wert zurück, der auf einen Fehler hinweist, sodass Fehler den Aufrufstapel sprudeln lassen und bei Bedarf verwendet werden können (prozedural / C-Methode). So wie C ++ Sie nicht zwingt, Ausnahmen zu verwenden (Sie können errno verwenden), sollte Python es auch nicht erzwingen
Braden Best
@BradenBest Die Validierung von JSON-Zeichenfolgen wird von dem Dämon verfolgt, der das Problem des Anhaltens interessant macht. Es gibt keine mathematisch korrekte Möglichkeit, die Richtigkeit einer Zeichenfolge zu beweisen, außer Ihre Zeichenfolge mit einem Parser zu testen und festzustellen, ob sie fehlerfrei endet. Um zu sehen, warum es schwierig ist: "Schreiben Sie mir ein Programm, das beweist, dass in einem Computerprogramm keine Syntaxfehler vorhanden sind". Das ist doch nicht möglich. Sprachentwickler werden poetisch über das ewige Wettrüsten des Kodierens und Dekodierens. Das Beste, was wir tun können, ist, Ja / Nein zurückzugeben, wenn eine Zeichenfolge für eine bestimmte Engine gültig ist, nicht für alle möglichen Engines.
Eric Leschinski
1
@EricLeschinski, aber hier gibt es kein Halteproblem. Das Programm löst eindeutig eine Ausnahme aus, wenn beim Parsen von JSON ein Fehler auftritt. Daher weiß das Programm, wann die JSON-Eingabe ungültig ist. Daher ist es zu 100% möglich, eine Funktion zu haben, die prüft, ob die Eingabe gültig ist, ohne sie verwenden zu müssen try. #StopCanaryAbuse
Braden Best
2

Ich würde sagen, das Parsen ist der einzige Weg, den man wirklich vollständig erkennen kann. Eine Ausnahme wird durch die Python- json.loads()Funktion (mit ziemlicher Sicherheit) ausgelöst, wenn nicht das richtige Format. Für die Zwecke Ihres Beispiels können Sie jedoch wahrscheinlich nur die ersten paar Nicht-Leerzeichen überprüfen ...

Ich bin nicht mit dem JSON vertraut, das Facebook zurücksendet, aber die meisten JSON-Zeichenfolgen von Web-Apps beginnen mit einem offenen Quadrat [oder einer geschweiften {Klammer. Keine mir bekannten Bildformate beginnen mit diesen Zeichen.

Wenn Sie hingegen wissen, welche Bildformate möglicherweise angezeigt werden, können Sie den Anfang der Zeichenfolge auf ihre Signaturen überprüfen, um Bilder zu identifizieren, und davon ausgehen, dass Sie JSON haben, wenn es sich nicht um ein Bild handelt.

Ein weiterer einfacher Hack zum Identifizieren einer Grafik anstelle einer Textzeichenfolge, falls Sie nach einer Grafik suchen, besteht darin, die ersten paar Dutzend Zeichen der Zeichenfolge auf Nicht-ASCII-Zeichen zu testen (vorausgesetzt, der JSON ist ASCII ).

Tim
quelle
0

Ich habe eine generische, interessante Lösung für dieses Problem gefunden:

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

und Sie können es so verwenden:

safe_json = SafeInvocator(json)
text = "{'foo':'bar'}"
item = safe_json.loads(text)
if item:
    # do something
odedlaz
quelle
1
Ich denke, allgemeine Lösungen sind gut, aber in diesem Fall kann die exceptKlausel jede ernsthafte Ausnahme verbergen. Das Fangen von Ausnahmen muss so restriktiv wie möglich sein.
Lucastamoios