Як перевірити, чи є строка дійсною JSON в Python?


184

У Python чи існує спосіб перевірити, чи є строка дійсною JSON, перш ніж спробувати її розібрати?

Наприклад, робота з такими речами, як API Graph Graph, іноді вона повертає JSON, іноді може повернути файл зображення.


3
api має встановити тип вмісту
John La Rooy

4
Ви не можете вказати, які дані повертаються у виклику API? Я не знайомий з API Facebook, але це звучить дуже дивно.
поштовх

Я робив один раз, але з codegolf способом
ВИ

1
Більшість відповідей - json, але, якщо ви називаєте фотографію профілю, воно просто повертає jpg
Joey Blake,

Відповіді:


234

Ви можете спробувати зробити json.loads(), що буде кидати a, ValueErrorякщо рядок, який ви пропускаєте, не може бути декодований як JSON.

Взагалі, філософія " пітонічного " для подібної ситуації називається EAFP , щоб простіше просити прощення, ніж дозволу .


4
Я бачу, як це буде працювати. Веде мене до мого наступного питання. Він кидає ValueError. У цьому моменті я хочу, щоб це було повернути рядок, який може ображати, щоб я міг зробити щось інше з ним. Поки що я отримав лише повідомлення про помилку та тип.
Joey Blake

2
Що поганого в тому, щоб повернути рядок, який ви передали, loadsза винятком пункту?
Джон Плоскість

1
нічого поганого в цьому, просто noob помилка з мого боку. Здається, я просто не можу викликати file.read () двічі. Але я можу встановити змінну і використовувати її. І ось що я зробив.
Joey Blake

5
лише примітка ... json.loads ('10 ') не кидає ValueError, і я впевнений, що "10" не є дійсним json ...
wahrheit

4
Незважаючи на те, що специфікація говорить про те, що текст JSON повинен бути масивом або об'єктом, більшість кодерів і декодерів (включаючи Python) будуть працювати з будь-яким значенням JSON у верхній частині, включаючи цифри та рядки. 10- дійсне значення числа JSON.
Джон Плоскість

145

Приклад сценарію Python повертає булевий файл, якщо рядок дійсна json:

import json

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

Які відбитки:

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 в словник Python:

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

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

Перетворіть об’єкт python в рядок JSON:

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

Якщо ви хочете отримати доступ до синтаксичного розбору, не скочуйте свою власну, використовуйте наявну бібліотеку: http://www.json.org/

Чудовий підручник з модуля JSON пітона: https://pymotw.com/2/json/

Чи є рядок JSON і показує синтаксичні помилки та повідомлення про помилки:

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

Друкує:

, 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 здатний перевіряти синтаксис, аналізувати, закріплювати, кодувати, декодувати тощо:

https://metacpan.org/pod/json_xs


Як ви вважаєте, ми повинні del json_objectколись підтвердити?
Акшай

4
Чому, пекло, не існує належного методу перевірки? Повинен бути спосіб перевірки помилок, не вбиваючи канарок.
Бреден Кращий

Те, що я отримую, це: лише тому, що Python дозволяє виконувати OO, не означає, що нормально ігнорувати інші частини. Я повинен мати можливість або А. відмовляти функцію відмови і використовувати винятки (спосіб OO / Python), або B. викликати функцію, яка повертає значення (успіх чи помилка) замість того, щоб викидати виняток, а потім мати свою функцію , у свою чергу, повертає дозорне значення, яке вказує на помилку, так що помилки переповнюють стек виклику і можуть використовуватися за необхідності (процедурний / спосіб C). Так само як C ++ не змушує вас використовувати винятки (ви можете використовувати errno), Python також не повинен це змушувати
Braden Best

@BradenBest Перевірка рядка JSON переслідує демон, що робить проблему зупинки цікавою. Немає математично правильного способу довести правильність рядка, окрім того, щоб спробувати рядок за допомогою аналізатора і побачити, чи закінчується він без помилок. Щоб зрозуміти, чому це важко: "Напишіть мені програму, яка підтверджує, що в комп'ютерній програмі немає синтаксичних помилок". Це неможливо. Мовні розробники будуть вільно поетично розповідати про вічну гонку озброєння кодування та розшифровки. Найкраще, що ми можемо зробити, - це повернути так / ні, якщо рядок дійсна для даного двигуна, а не для всіх можливих двигунів.
Ерік Лещинський

1
@EricLeschinski, але тут немає проблеми з зупинкою. Програма явно створює виняток, якщо під час розбору JSON виникає помилка. Тому програма знає, коли вхід JSON недійсний. Отже, на 100% можливо мати функцію, яка перевіряє, чи введений вхід дійсний, не використовуючи try. #StopCanaryAbuse
Braden Best

2

Я б сказав, що це розбір - це єдиний спосіб, який ви можете реально повністю сказати. Виняток буде підвищено функцією python json.loads()(майже напевно), якщо не правильним форматом. Однак для цілей вашого прикладу ви, ймовірно, можете просто перевірити першу пару символів, які не пробіли ...

Я не знайомий з JSON, який facebook надсилає назад, але більшість рядків JSON з веб-додатків розпочнеться з відкритого квадрата [або фігурної {дужки. Я не знаю форматів зображень, які я починаю з цих символів.

І навпаки, якщо ви знаєте, які формати зображень можуть відображатися, ви можете перевірити початок рядка на наявність їх підписів, щоб виявити зображення, і припустити, що у вас JSON, якщо це не зображення.

Ще один простий хак для виявлення графічного, а не текстового рядка, у випадку, якщо ви шукаєте графіку, - це просто перевірити наявність символів, що не належать до ASCII, у першій пару десятків символів рядка (припустимо, що JSON - ASCII ).


0

Я придумав загальне, цікаве рішення цієї проблеми:

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

і ви можете використовувати його так:

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

1
Я думаю, загальні рішення хороші, але в цьому випадку ця exceptстаття може приховувати будь-який серйозний виняток. Винятки з лову повинні бути максимально обмежуючими.
lucaastamoios
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.