Bagaimana cara saya memeriksa apakah string JSON valid dengan Python?

184

Dalam Python, apakah ada cara untuk memeriksa apakah string JSON yang valid sebelum mencoba menguraikannya?

Misalnya bekerja dengan hal-hal seperti Facebook Graph API, kadang-kadang mengembalikan JSON, kadang-kadang bisa mengembalikan file gambar.

Joey Blake
sumber
3
api harus mengatur tipe konten
John La Rooy
4
Anda tidak dapat menentukan data apa yang dikembalikan dalam panggilan API? Saya tidak terbiasa dengan API Facebook tetapi itu terdengar sangat aneh.
jhocking
Saya telah melakukan sekali, tetapi dengan cara codegolf
ANDA
1
Sebagian besar tanggapannya adalah json, tetapi, jika Anda memanggil foto profil, itu hanya mengembalikan jpg
Joey Blake

Jawaban:

235

Anda dapat mencoba melakukannya json.loads(), yang akan melempar ValueErrorjika string yang Anda berikan tidak dapat diterjemahkan sebagai JSON.

Secara umum, filosofi " Pythonic " untuk situasi seperti ini disebut EAFP , agar Lebih Mudah Meminta Pengampunan daripada Izin .

John Flatness
sumber
4
Saya bisa melihat bagaimana itu akan berhasil. Menuntun saya ke pertanyaan saya berikutnya. Itu melempar ValueError. Apa yang ingin saya lakukan pada titik ini adalah mengembalikan string yang menyinggung sehingga saya dapat melakukan sesuatu yang lain dengannya. Sejauh ini, saya hanya mendapatkan pesan kesalahan dan ketik.
Joey Blake
2
Apa yang salah dengan mengembalikan string yang Anda berikan ke loadsdalam kecuali klausa?
John Flatness
1
tidak ada yang salah dengan itu, hanya kesalahan noob di pihak saya. Tampaknya saya tidak bisa memanggil file.read () dua kali. Tapi saya bisa mengatur variabel dan menggunakannya. Dan itulah yang saya lakukan.
Joey Blake
5
hanya sebuah catatan ... json.loads ('10 ') tidak melempar ValueError dan saya yakin' 10 'bukan json yang valid ...
wahrheit
4
Terlepas dari kenyataan bahwa spesifikasi mengatakan bahwa teks JSON harus berupa array atau objek, sebagian besar penyandi dan pengurai kode (termasuk Python) akan bekerja dengan nilai JSON apa pun di "atas," termasuk angka dan string. 10adalah nilai nomor JSON yang valid.
John Flatness
145

Contoh skrip Python mengembalikan boolean jika string valid json:

import json

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

Yang mencetak:

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

Mengonversi string JSON ke kamus Python:

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

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

Ubah objek python menjadi string JSON:

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

Jika Anda ingin akses ke penguraian level rendah, jangan roll milik Anda sendiri, gunakan perpustakaan yang ada: http://www.json.org/

Tutorial hebat tentang modul JSON python: https://pymotw.com/2/json/

Apakah String JSON dan tampilkan kesalahan sintaksis dan pesan kesalahan:

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

Cetakan:

, 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 mampu memeriksa sintaksis, parsing, prittifying, encoding, decoding dan banyak lagi:

https://metacpan.org/pod/json_xs

Eric Leschinski
sumber
Apakah Anda pikir kami harus del json_objectsekali memvalidasi?
Akshay
4
Kenapa tidak ada metode validasi yang tepat? Seharusnya ada cara untuk memeriksa kesalahan tanpa membunuh kenari.
Braden Best
Yang saya maksudkan adalah: Hanya karena Python memungkinkan untuk OO tidak berarti tidak apa-apa untuk mengabaikan bagian lain. Saya harus memiliki opsi untuk A. membiarkan fungsi gagal dan menggunakan pengecualian (cara OO / Python), atau B. memanggil fungsi yang mengembalikan nilai (keberhasilan atau kesalahan) alih-alih melemparkan pengecualian, dan kemudian memiliki fungsi saya , pada gilirannya, mengembalikan nilai sentinel yang menunjukkan kesalahan, sehingga kesalahan menggelembungkan tumpukan panggilan dan dapat digunakan seperlunya (cara prosedural / C). Sama seperti C ++ tidak memaksa Anda untuk menggunakan pengecualian (Anda dapat menggunakan errno), Python juga tidak boleh memaksakannya
Braden Best
@BradenBest Validasi string JSON dihantui oleh iblis yang membuat masalah penghentian menarik. Tidak ada cara yang benar secara matematis untuk membuktikan kebenaran suatu string kecuali untuk mencoba string Anda dengan parser dan melihat apakah itu selesai tanpa kesalahan. Untuk mengetahui mengapa ini sulit: "Tuliskan saya sebuah program yang membuktikan tidak ada kesalahan sintaksis dalam program komputer". Itu tidak mungkin. Pengembang bahasa akan menjadi puitis tentang perlombaan encoding dan decoding senjata abadi. Yang terbaik yang bisa kita lakukan adalah mengembalikan ya / tidak jika string valid untuk mesin yang diberikan, bukan untuk semua mesin yang mungkin.
Eric Leschinski
1
@EricLeschinski tetapi tidak ada masalah berhenti di sini. Program ini dengan jelas memunculkan pengecualian jika terjadi kesalahan saat mem-parsing JSON. Oleh karena itu, program tahu kapan input JSON tidak valid. Oleh karena itu, 100% dimungkinkan untuk memiliki fungsi yang memeriksa apakah input tersebut valid tanpa harus menggunakan try. #StopCanaryAbuse
Braden Best
2

Saya akan mengatakan parsing itu adalah satu-satunya cara Anda dapat benar-benar tahu. Pengecualian akan dimunculkan oleh json.loads()fungsi python (hampir pasti) jika bukan format yang benar. Namun, tujuan dari contoh Anda, Anda mungkin hanya dapat memeriksa beberapa karakter non-spasi putih pertama ...

Saya tidak terbiasa dengan JSON yang dikirim kembali oleh facebook, tetapi sebagian besar string JSON dari aplikasi web akan mulai dengan kotak terbuka [atau keriting{ braket . Tidak ada format gambar yang saya tahu mulai dengan karakter itu.

Sebaliknya jika Anda tahu format gambar apa yang mungkin muncul, Anda dapat memeriksa awal string untuk tanda tangan mereka untuk mengidentifikasi gambar, dan menganggap Anda memiliki JSON jika bukan gambar.

Peretasan sederhana lainnya untuk mengidentifikasi grafik, daripada string teks, dalam kasus Anda mencari grafik, hanya untuk menguji karakter non-ASCII dalam beberapa lusin karakter pertama dari string (dengan asumsi JSON adalah ASCII ).

Tim
sumber
0

Saya datang dengan solusi generik dan menarik untuk masalah ini:

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

dan Anda dapat menggunakannya seperti ini:

safe_json = SafeInvocator(json)
text = "{'foo':'bar'}"
item = safe_json.loads(text)
if item:
    # do something
odedlaz
sumber
1
Saya pikir solusi umum bagus, tetapi dalam hal ini, exceptklausa dapat menyembunyikan pengecualian serius. Pengecualian penangkapan harus seketat mungkin.
lucastamoios