Python: json.loads дросселирует на экранах

У меня есть приложение, которое отправляет объект JSON (в формате Prototype) на сервер ASP. На сервере модуль Python 2.6 "json" пытается загрузить() JSON, но он задыхается от некоторой комбинации обратных косых черт. Обратите внимание:

>>> s
'{"FileExists": true, "Version": "4.3.2.1", "Path": "\\\\host\\dir\\file.exe"}'

>>> tmp = json.loads(s)
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
  {... blah blah blah...}
  File "C:\Python26\lib\json\decoder.py", line 155, in JSONString
    return scanstring(match.string, match.end(), encoding, strict)
  ValueError: Invalid \escape: line 1 column 58 (char 58)

>>> s[55:60]
u'ost\\d'

Итак, столбец 58 - это escape-обратная косая черта. Я думал, что это БЫЛО правильно сбежало! UNC \\host\dir\file.exe, поэтому я просто удвоился на косых чертах. Но, видимо, это нехорошо. Может кто-нибудь помочь? В крайнем случае я планирую конвертировать\в/, а затем обратно, но это кажется настоящим взломом для меня.

Спасибо заранее!

Ответ 1

Правильный json:

r'{"FileExists": true, "Version": "4.3.2.1", "Path": "\\\\host\\dir\\file.exe"}'

Обратите внимание на букву r, если вы ее опустите, вам нужно также выйти из \ для Python.

>>> import json
>>> d = json.loads(s)
>>> d.keys()
[u'FileExists', u'Path', u'Version']
>>> d.values()
[True, u'\\\\host\\dir\\file.exe', u'4.3.2.1']

Обратите внимание на разницу:

>>> repr(d[u'Path'])
"u'\\\\\\\\host\\\\dir\\\\file.exe'"
>>> str(d[u'Path'])
'\\\\host\\dir\\file.exe'
>>> print d[u'Path']
\\host\dir\file.exe

Python REPL печатает по умолчанию repr(obj) для объекта obj:

>>> class A:
...   __str__ = lambda self: "str"
...   __repr__  = lambda self: "repr"
... 
>>> A()
repr
>>> print A()
str

Поэтому ваша оригинальная строка s неправильно экранирована для JSON. Он содержит unescaped '\d' и '\f'. print s должен показывать '\\d', в противном случае это неверно JSON.

ПРИМЕЧАНИЕ. Строка JSON представляет собой набор из нулей или более символов Unicode, заключенных в двойные кавычки, с использованием обратных слэшей (json.org). Я пропустил проблемы с кодировкой (а именно, преобразование из строк байтов в unicode и наоборот) в приведенных выше примерах.

Ответ 2

Так как исключение дает вам индекс нарушающего escape-символа, этот небольшой взлом, который я разработал, может быть приятным:)

def fix_JSON(json_message=None):
    result = None
    try:        
        result = json.loads(json_message)
    except Exception as e:      
        # Find the offending character index:
        idx_to_replace = int(e.message.split(' ')[-1].replace(')',''))      
        # Remove the offending character:
        json_message = list(json_message)
        json_message[idx_to_replace] = ' '
        new_message = ''.join(json_message)     
        return fix_JSON(json_message=new_message)
    return result

Ответ 3

>>> s
'{"FileExists": true, "Version": "4.3.2.1", "Path": "\\\\host\\dir\\file.exe"}'
>>> print s
{"FileExists": true, "Version": "4.3.2.1", "Path": "\\host\dir\file.exe"}

Вы фактически не избежали строки, поэтому пытались разобрать недопустимые escape-коды, например \d или \f. Рассмотрите возможность использования проверенного JSON-кодировщика, такого как json2.js.