Как автоматически исправить недопустимую строку JSON?

Из API 2gis я получил следующую строку JSON.

{ "api_version": "1.3", "response_code": "200", "id": "3237490513229753", "lon": "38.969916127827", "lat": "45.069889625267", "page_url": null, "name": "ATB", "firm_group": { "id": "3237499103085728", "count": "1" }, "city_name": "Krasnodar", "city_id": "3237585002430511", "address": "Turgeneva, 172/1", "create_time": "2008-07-22 10:02:04 07", "modification_time": "2013-08-09 20:04:36 07", "see_also": [ { "id": "3237491513434577", "lon": 38.973110606808, "lat": 45.029031222211, "name": "Advance", "hash": "5698hn745A8IJ1H86177uvgn94521J3464he26763737242Cf6e654G62J0I7878e", "ads": { "sponsored_article": { "title": "Center "ADVANCE"", "text": "Business.English." }, "warning": null } } ] } 

Но Python не распознает это:

  • Игнорировать str.format (** foo), если ключ не существует в foo
  • Как избежать одиночных кавычек в Python на сервере, которые будут использоваться в Javascript на клиенте
  • Как обнаружить нажатие клавиши ESCape в Python?
  • Как я могу выборочно избежать процентов (%) в строках Python?
  • Как я могу избежать двоеточий в имени атрибута с ElementTree Python?
  • Самый простой способ удалить unicode-представления из строки в python 3?
  •  json.loads(firm_str) 

    Ожидание, разделитель: строка 1 столбца 3646 (char 3645)

    Это выглядит как проблема с котировками в: «title»: «Центр« ADVANCE »"

    Как я могу исправить это автоматически в Python?

  • Python Сжатие серии объектов JSON при сохранении последовательного чтения?
  • Проблема с пинтовым сервером шины Azure
  • Возьмем строку JSON, развязав ее в интерфейс на карте , редактируем и маршализируем ее в байт, кажется более сложным, тогда это должно быть
  • Преобразование csv в json с помощью python
  • Отображение лучшего сообщения об ошибке, чем «Нет объекта JSON можно декодировать»
  • Импортирование ошибочно конкатенированных JSON в python
  • 5 Solutions collect form web for “Как автоматически исправить недопустимую строку JSON?”

    Ответ от @Michael дал мне идею … не очень красивая идея, но, похоже, она работает, по крайней мере, на вашем примере: попробуйте разобрать строку JSON, и если она не удалась, найдите символ, в котором он не удался строка исключения и замените этот символ.

     while True: try: result = json.loads(s) # try to parse... break # parsing worked -> exit loop except Exception as e: # "Expecting , delimiter: line 34 column 54 (char 1158)" # position of unexpected character after '"' unexp = int(re.findall(r'\(char (\d+)\)', str(e))[0]) # position of unescaped '"' before that unesc = s.rfind(r'"', 0, unexp) s = s[:unesc] + r'\"' + s[unesc+1:] # position of correspondig closing '"' (+2 for inserted '\') closg = s.find(r'"', unesc + 2) s = s[:closg] + r'\"' + s[closg+1:] print result 

    Вы можете добавить дополнительные проверки, чтобы это не закончилось в бесконечном цикле (например, при максимальном количестве повторений, так как в строке есть символы). Кроме того, это все равно не сработает, если на некорректном " за ним следует запятая, как указано @gnibbler.

    Обновление: похоже, сейчас это работает довольно хорошо (хотя все еще не идеально), даже если у небезопасного " следует запятая или закрывающая скобка, так как в этом случае она, скорее всего, получит жалобу на синтаксическую ошибку после этого (ожидаемое свойство имя и т. д.) и вернуться к последнему " . Он также автоматически ускользает от соответствующего закрытия " (при условии, что он есть).

    Если это именно то, что возвращает API, тогда возникает проблема с их API. Это недопустимо JSON. Особенно в этой области:

     "ads": { "sponsored_article": { "title": "Образовательный центр "ADVANCE"", <-- here "text": "Бизнес.Риторика.Английский язык.Подготовка к школе.Подготовка к ЕГЭ." }, "warning": null } 

    Двойные кавычки вокруг ADVANCE не сбрасываются. Вы можете сказать, используя что-то вроде http://jsonlint.com/, чтобы проверить его.

    Это проблема с тем, что " не ускользает, данные плохие в источнике, если это то, что вы получаете. Им нужно исправить это.

     Parse error on line 4: ...азовательный центр "ADVANCE"", -----------------------^ Expecting '}', ':', ',', ']' 

    Это устраняет проблему:

     "title": "Образовательный центр \"ADVANCE\"", 

    Единственное реальное и окончательное решение – 2gis, чтобы исправить их API.

    Тем временем можно исправить неправильно закодированные двойные кавычки JSON внутри строк. Если за каждой парой ключ-значение следует новая строка (как представляется, из опубликованных данных), следующая работа будет выполняться следующим образом:

     def fixjson(badjson): s = badjson idx = 0 while True: try: start = s.index( '": "', idx) + 4 end1 = s.index( '",\n',idx) end2 = s.index( '"\n', idx) if end1 < end2: end = end1 else: end = end2 content = s[start:end] content = content.replace('"', '\\"') s = s[:start] + content + s[end:] idx = start + len(content) + 6 except: return s 

    Пожалуйста, обратите внимание, что некоторые допущения сделаны:

    Функция позволяет избежать двойных кавычек внутри строки значений, принадлежащей парам ключ-значение.

    Предполагается, что текст, который должен быть экранирован, начинается после последовательности

     ": " 

    и заканчивается перед последовательностью

     ",\n 

    или

     "\n 

    Передача отправленного JSON функции возвращает это возвращаемое значение

     { "api_version": "1.3", "response_code": "200", "id": "3237490513229753", "lon": "38.969916127827", "lat": "45.069889625267", "page_url": null, "name": "ATB", "firm_group": { "id": "3237499103085728", "count": "1" }, "city_name": "Krasnodar", "city_id": "3237585002430511", "address": "Turgeneva, 172/1", "create_time": "2008-07-22 10:02:04 07", "modification_time": "2013-08-09 20:04:36 07", "see_also": [ { "id": "3237491513434577", "lon": 38.973110606808, "lat": 45.029031222211, "name": "Advance", "hash": "5698hn745A8IJ1H86177uvgn94521J3464he26763737242Cf6e654G62J0I7878e", "ads": { "sponsored_article": { "title": "Center \"ADVANCE\"", "text": "Business.English." }, "warning": null } } ] } 

    Имейте в виду, что вы можете легко настроить функцию, если ваши потребности не полностью удовлетворены.

    Вам нужно избегать двойных кавычек в строках JSON, как показано ниже:

     "title": "Образовательный центр \\"ADVANCE\\"", 

    Чтобы исправить это программно, самым простым способом было бы изменить ваш парсер JSON, чтобы у вас был какой-то контекст для ошибки, а затем попытайтесь его исправить.

    Вышеупомянутая идея хороша, но у меня была проблема с этим. Мой json Sting состоял только в одной дополнительной двойной кавычки. Итак, я исправил вышеупомянутый код.

    JsonStr был

     { "api_version": "1.3", "response_code": "200", "id": "3237490513229753", "lon": "38.969916127827", "lat": "45.069889625267", "page_url": null, "name": "ATB", "firm_group": { "id": "3237499103085728", "count": "1" }, "city_name": "Krasnodar", "city_id": "3237585002430511", "address": "Turgeneva, 172/1", "create_time": "2008-07-22 10:02:04 07", "modification_time": "2013-08-09 20:04:36 07", "see_also": [ { "id": "3237491513434577", "lon": 38.973110606808, "lat": 45.029031222211, "name": "Advance", "hash": "5698hn745A8IJ1H86177uvgn94521J3464he26763737242Cf6e654G62J0I7878e", "ads": { "sponsored_article": { "title": "Center "ADVANCE", "text": "Business.English." }, "warning": null } } ] } 

    Исправление:

     import json, re def fixJSON(jsonStr): # Substitue all the backslash from JSON string. jsonStr = re.sub(r'\\', '', jsonStr) try: return json.loads(jsonStr) except ValueError: while True: # Search json string specifically for '"' b = re.search(r'[\w|"]\s?(")\s?[\w|"]', jsonStr) # If we don't find any the we come out of loop if not b: break # Get the location of \" s, e = b.span(1) c = jsonStr[s:e] # Replace \" with \' c = c.replace('"',"'") jsonStr = jsonStr[:s] + c + jsonStr[e:] return json.loads(jsonStr) 

    Этот код также работает для строки JSON, указанной в описании проблемы


    ИЛИ вы также можете это сделать:

     def fixJSON(jsonStr): # First remove the " from where it is supposed to be. jsonStr = re.sub(r'\\', '', jsonStr) jsonStr = re.sub(r'{"', '{`', jsonStr) jsonStr = re.sub(r'"}', '`}', jsonStr) jsonStr = re.sub(r'":"', '`:`', jsonStr) jsonStr = re.sub(r'":', '`:', jsonStr) jsonStr = re.sub(r'","', '`,`', jsonStr) jsonStr = re.sub(r'",', '`,', jsonStr) jsonStr = re.sub(r',"', ',`', jsonStr) jsonStr = re.sub(r'\["', '\[`', jsonStr) jsonStr = re.sub(r'"\]', '`\]', jsonStr) # Remove all the unwanted " and replace with ' ' jsonStr = re.sub(r'"',' ', jsonStr) # Put back all the " where it supposed to be. jsonStr = re.sub(r'\`','\"', jsonStr) return json.loads(jsonStr) 
    Python - лучший язык программирования в мире.