2009-10-01 24 views
11

Tengo una aplicación que está enviando un objeto JSON (formateado con Prototype) a un servidor ASP. En el servidor, el módulo "json" de Python 2.6 intenta cargar() el JSON, pero se está ahogando en una combinación de barras invertidas. Observe:Python: json.loads se ahoga en escapes

>>> 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' 

Así que la columna 58 es la fuga-backslash. ¡Pensé que esto FUE escapado correctamente! UNC es \\host\dir\file.exe, así que simplemente dupliqué en barras. Pero aparentemente esto no es bueno. ¿Alguien puede ayudar? Como último recurso, estoy considerando convertir el \ a/y luego volver otra vez, pero esto parece un verdadero truco para mí.

¡Gracias de antemano!

Respuesta

16

El JSON correcta es:

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

verifique la letra r si se omite se tiene que escapar \ para Python también.

>>> 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'] 

nota la diferencia:

>>> 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 

impresiones Python REPL por defecto el repr(obj) para un objeto obj:

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

lo tanto, su cadena original s no se escapó adecuadamente para JSON. Contienesin protección y '\f'. print s debe mostrar '\\d' de lo contrario no es JSON correcto.

NOTA: cadena JSON es una colección de cero o más caracteres Unicode, envueltos entre comillas dobles, utilizando escapes de barra invertida (json.org). Me he saltado los problemas de codificación (es decir, la transformación de cadenas de bytes a Unicode y viceversa) en los ejemplos anteriores.

+0

:) >>> s = r '{ "FileExists": true , "Versión": "4.3.2.1", "Ruta": "\\\\ host \\ dir \\ file.exe"} ' >>> json.load (s) {u'FileExists' : Es cierto, u'Path ': u' \\\\ host \\ dir \\ file.exe ', u'Version': u'4.3.2.1 '} – Chris

+0

Entonces, ¿qué está haciendo en realidad? ¿Cómo puedo aplicarlo a una cadena que ya está almacenada como, por ejemplo, "foo"? ¿Es algún tipo de codificación? – Chris

+0

''s ='' rompe el formateo. – jfs

1
>>> 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"} 

En realidad no se ha escapado de la cadena, por lo que es intentar analizar los códigos de escape no válidos como \d o \f. Considere usar un codificador JSON bien probado, como json2.js.

2

Desde la excepción le da el índice del carácter ofensivo de escape, este pequeño truco que he desarrollado podría ser bueno :)

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 
+1

Gracias por el código. En mi caso (Python 3.5), tuve que cambiar 'idx_to_replace = int (e.message.split ('') [- 1] .replace (')', ''))' to 'idx_to_replace = int (str (e) .split ('') [- 1] .replace (')', '')) ' – TitanFighter

Cuestiones relacionadas