Python'da bir dizenin geçerli JSON olup olmadığını nasıl kontrol edebilirim?


184

Python'da, bir dizeyi ayrıştırmaya çalışmadan önce geçerli bir JSON olup olmadığını kontrol etmenin bir yolu var mı?

Örneğin, Facebook Graph API gibi şeylerle çalışırken bazen JSON, bazen de bir görüntü dosyası döndürebilir.


3
API içerik türünü ayarlamalıdır
John La Rooy 2

4
API çağrısında hangi verilerin döndürüleceğini belirleyemiyor musunuz? Facebook API'sine aşina değilim ama kulağa tuhaf geliyor.
jhocking

Ben bir kez yapılır, var ama ile codegolf şekilde
SİZ

1
Yanıtların çoğu json, ancak profil fotoğrafını çağırırsanız sadece jpg döndürür
Joey Blake

Yanıtlar:


235

Yapmayı deneyebilirsiniz json.loads(), bu da geçirdiğiniz ValueErrordizenin kodu JSON olarak çözülemezse bir atar .

Genel olarak, " Pythonic durumun bu tür" felsefesi denir EAFP için, mağfiret daha izin isteyin daha kolay .


4
Bunun nasıl işlediğini görebiliyorum. Beni bir sonraki soruma götürüyor. Bir ValueError atar. Ne bu noktada yapmak istiyorum onunla başka bir şey yapabilirsiniz böylece rahatsız edici dize dönmektir. Şimdiye kadar sadece hata mesajını ve türünü aldım.
Joey Blake

2
loadsDışında belirtilen maddede geçtiğiniz dizeyi döndürmenin nesi yanlış ?
John Flatness

1
bunda yanlış bir şey yok, sadece benim için bir noob hatası. Görünüşe göre sadece iki kez file.read () çağrısı yapamıyorum. Ama bir değişken ayarlayıp kullanabilirim. Ve ben de öyle yaptım.
Joey Blake

5
sadece bir not ... json.loads ('10 ') ValueError atmaz ve eminim' 10 'geçerli bir json değildir ...
wahrheit

4
Spesifikasyon bir JSON metninin bir dizi veya nesne olması gerektiğini söylese de, çoğu kodlayıcı ve kod çözücü (Python'lar dahil), sayılar ve dizeler dahil olmak üzere "üstteki" herhangi bir JSON değeriyle çalışacaktır. 10geçerli bir JSON numarası değeridir.
John Flatness

145

Bir dize geçerliyse örnek Python betiği bir boole döndürür json:

import json

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

Hangi baskılar:

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

JSON dizesini Python sözlüğüne dönüştürme:

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

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

Python nesnesini JSON dizesine dönüştürme:

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

Düşük düzeyli ayrıştırmaya erişmek istiyorsanız kendi kitaplığınızı döndürmeyin, mevcut bir kitaplığı kullanın: http://www.json.org/

Python JSON modülünde harika öğretici: https://pymotw.com/2/json/

String JSON ve sözdizimi hatalarını ve hata mesajlarını göster:

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

Baskılar:

, 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 sözdizimi denetimi, ayrıştırma, hassaslaştırma, kodlama, kod çözme ve daha fazlasını yapabilir:

https://metacpan.org/pod/json_xs


Sence bir del json_objectkez valide etmemiz gerekir mi?
Akshay

4
Neden doğru bir doğrulama yöntemi yok? Kanaryaları öldürmeden hata kontrolü yapmanın bir yolu olmalı.
Braden Best

Şu an elde ettiğim şey: Python'un OO'ya izin vermesi, diğer parçaları görmezden gelmenin iyi olduğu anlamına gelmiyor. Ben işlev başarısız olmasına izin ve istisnalar (OO / Python yolu) kullanarak veya bir istisna atmak yerine bir değer (başarı veya hata) döndüren bir işlevi çağıran ve sonra benim işlev sahip bir seçenek olmalıdır. , sırayla, bir hata olduğunu belirten bir sentinel değeri döndürün, böylece hatalar çağrı yığınını başlatır ve gerektiği şekilde kullanılabilir (prosedürel / C yolu). Nasıl C ++ istisnaları kullanmaya zorlamıyorsa (errno kullanabilirsiniz), Python da zorlamamalıdır
Braden Best

@BradenBest JSON dize doğrulaması, durma sorununu ilginç kılan şeytan tarafından perili. Dizenizi bir ayrıştırıcıyla denemek ve hatasız bitip bitmediğini görmek dışında, bir dizenin doğruluğunu kanıtlamanın matematiksel olarak doğru bir yolu yoktur. Neden zor olduğunu görmek için: "Bana bir bilgisayar programında sözdizimi hatası olmadığını kanıtlayan bir program yazın". Bu mümkün değil. Dil geliştiricileri, kodlama ve kod çözmenin sonsuz silahlanma ırkı hakkında şiirsel olacaklar. Yapabileceğimiz en iyi şey, olası bir motor için değil, belirli bir motor için bir dize geçerliyse evet / hayır döndürmektir.
Eric Leschinski

1
@EricLeschinski ama burada bir durma problemi yok. JSON ayrıştırılırken bir hata oluşursa program açıkça bir istisna oluşturur. Bu nedenle, program JSON girişinin ne zaman geçersiz olduğunu bilir. Bu nedenle, girişin kullanılmadan geçerli olup olmadığını kontrol eden bir fonksiyona sahip olmak% 100 mümkündür try. #StopCanaryAbuse
Braden En İyi

2

Ayrıştırmayı gerçekten tamamen anlamanın tek yolu olduğunu söyleyebilirim. İstisna json.loads(), doğru format değilse python işlevi (neredeyse kesinlikle) tarafından yükseltilecektir . Ancak, örneğinizin amaçları muhtemelen boşluk olmayan karakterlerin ilk çiftini kontrol edebilirsiniz ...

Facebook'un geri gönderdiği JSON'a aşina değilim, ancak web uygulamalarından çoğu JSON dizesi açık bir kare [veya kıvırcık {parantez ile başlayacak . Bu karakterlerle başladığımı bildiğim görüntü formatları yok.

Tersine, hangi görüntü formatlarının görünebileceğini biliyorsanız, görüntüleri tanımlamak için dizelerinin başlangıcını imzalarını kontrol edebilir ve görüntü değilse JSON'a sahip olduğunuzu varsayabilirsiniz.

Bir grafik arıyorsanız, bir metin dizesi yerine bir grafiği tanımlamak için başka bir basit saldırı, dizenin ilk birkaç düzine karakterindeki ASCII olmayan karakterleri test etmektir (JSON'un ASCII olduğunu varsayarsak) ).


0

Bu soruna genel, ilginç bir çözüm buldum:

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

ve şu şekilde kullanabilirsiniz:

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

1
Genel çözümlerin iyi olduğunu düşünüyorum, ancak bu durumda, exceptmadde herhangi bir ciddi istisnayı gizleyebilir. Yakalama istisnaları mümkün olduğunca kısıtlayıcı olmalıdır.
lucastamoios
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.