Как проверить, является ли строка допустимым JSON в Python?

184

В Python есть ли способ проверить, является ли строка допустимым JSON, прежде чем пытаться ее проанализировать?

Например, работая с такими вещами, как Facebook Graph API, иногда он возвращает JSON, иногда он может вернуть файл изображения.

Джои Блейк
источник
3
API должен установить тип содержимого
John La Rooy
4
Вы не можете указать, какие данные возвращаются в вызове API? Я не знаком с API Facebook, но это звучит очень странно.
Джоккинг
Я сделал один раз, но с codegolf способом
ВЫ
1
Большинство ответов - json, но, если вы позвоните на фотографию профиля, он просто вернет jpg
Джои Блейк,

Ответы:

235

Вы можете попытаться это сделать json.loads(), что приведет к выдаче, ValueErrorесли передаваемая строка не может быть декодирована как JSON.

В общем, философия " Pythonic " для такого рода ситуаций называется EAFP , так как Проще просить прощения, чем разрешения .

Джон Флэтнесс
источник
4
Я вижу, как это будет работать. Приводит меня к следующему вопросу. Выдает ValueError. На этом этапе я хочу вернуть строку, которая нарушает правила, чтобы я мог сделать с ней что-то еще. До сих пор я получил только сообщение об ошибке и тип.
Джои Блейк,
2
Что плохого в том, чтобы просто вернуть строку, которую вы передали loadsв предложении кроме?
Джон Флатнесс
1
в этом нет ничего плохого, просто ошибка с моей стороны. Похоже, я просто не могу вызвать file.read () дважды. Но я могу установить переменную и использовать ее. И вот что я сделал.
Джои Блейк
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/

Отличное руководство по Python-модулю 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 способен проверять синтаксис, анализировать, prittifying, кодировать, декодировать и многое другое:

https://metacpan.org/pod/json_xs

Эрик Лещинский
источник
Как вы думаете, мы должны del json_objectкогда-то проверить?
Акшай
4
Почему, черт возьми, нет правильного метода проверки? Должен быть способ проверки ошибок без убийства канареек.
Брэден Бест
То, к чему я клоню: только то, что Python допускает OO, не означает, что можно игнорировать другие части. У меня должна быть возможность либо: A. позволить функции завершиться с ошибкой и использовать исключения (OO / Python), либо B. Вызвать функцию, которая возвращает значение (успех или ошибка) вместо выдачи исключения, а затем получить мою функцию. в свою очередь, возвращает значение часового, которое указывает на ошибку, так что ошибки пузырьков в стеке вызовов и могут быть использованы по мере необходимости (метод процедур / C). Так же, как C ++ не заставляет вас использовать исключения (вы можете использовать errno), Python также не должен форсировать это
Braden Best
@BradenBest Проверка строки JSON преследует демон, который делает проблему остановки интересной. Не существует математически правильного способа доказать правильность строки, кроме как попробовать вашу строку с парсером и посмотреть, завершится ли она без ошибок. Чтобы понять, почему это сложно: «Напишите мне программу, которая доказывает отсутствие синтаксических ошибок в компьютерной программе». Это невозможно. Разработчики языка будут поэтически относиться к вечной гонке вооружений кодирования и декодирования. Лучшее, что мы можем сделать, это вернуть yes / no, если строка действительна для данного движка, а не для всех возможных движков.
Эрик Лещинский
1
@EricLeschinski, но здесь нет проблем с остановкой. Программа явно вызывает исключение, если при синтаксическом анализе JSON возникает ошибка. Следовательно, программа знает, когда ввод JSON недопустим. Следовательно, на 100% возможно иметь функцию, которая проверяет, является ли ввод действительным без использования try. #StopCanaryAbuse
Брэден Бест
2

Я бы сказал, разбор это единственный способ, которым вы можете сказать полностью. Исключение будет вызвано json.loads()функцией Python (почти наверняка), если не правильный формат. Тем не менее, в целях вашего примера вы можете просто проверить первую пару непробельных символов ...

Я не знаком с 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
odedlaz
источник
1
Я думаю, что общие решения хороши, но в этом случае exceptпункт может скрыть любое серьезное исключение. Ловля исключений должна быть максимально ограничительной.
lucastamoios