No se puede analizar TAB en archivos JSON

Estoy encontrando un problema de análisis al cargar archivos JSON que parecen tener el carácter TAB en ellos.

Cuando voy a http://jsonlint.com/ , y entro en la parte con el carácter TAB:

{ "My_String": "Foo bar. Bar foo." } 

El validador se queja con:

 Parse error on line 2: { "My_String": "Foo bar. Bar foo." ------------------^ Expecting 'STRING', 'NUMBER', 'NULL', 'TRUE', 'FALSE', '{', '[' 

Esto es literalmente una copia / pegado del texto JSON ofensivo.

He intentado cargar este archivo con json y simplejson sin éxito. ¿Cómo puedo cargar esto correctamente? ¿Debo pre-procesar el archivo y reemplazar TAB por \t o por un espacio? ¿O hay algo que me estoy perdiendo aquí?

Actualizar:

Aquí también hay un ejemplo problemático en simplejson :

 foo = '{"My_string": "Foo bar.\t Bar foo."}' simplejson.loads(foo) JSONDecodeError: Invalid control character '\t' at: line 1 column 24 (char 23) 

Desde el estándar JSON :

Se permiten espacios en blanco insignificantes antes o después de cualquier token. Los caracteres de espacio en blanco son: tabulación de caracteres (U + 0009), salto de línea (U + 000A), retorno de carro (U + 000D) y espacio (U + 0020). No se permite el espacio en blanco dentro de ningún token, excepto que se permite el espacio en las cadenas.

Significa que no se permite un carácter de tabulación literal dentro de una cadena JSON. Debe escapar de él como \t (en un archivo .json) :

 {"My_string": "Foo bar.\t Bar foo."} 

Además, si se proporciona texto json dentro de un literal de cadena de Python, entonces necesita doble escape de la pestaña:

 foo = '{"My_string": "Foo bar.\\t Bar foo."}' # in a Python source 

O usa un literal de cadena sin formato de Python:

 foo = r'{"My_string": "Foo bar.\t Bar foo."}' # in a Python source 

Las tabs son legales, ya que delimitan los espacios en blanco fuera de los valores, pero no dentro de las cadenas. Use \t lugar.

EDITAR: En base a sus comentarios, veo cierta confusión sobre qué es realmente una pestaña … el carácter de la pestaña es simplemente un carácter normal, como ‘a’ o ‘5’ o ‘.’ o cualquier otro carácter que ingrese presionando una tecla en su teclado. Toma un solo byte, cuyo valor numérico es 9. No hay barras invertidas ni t ‘minúsculas involucradas.

Lo que coloca la pestaña en una categoría diferente de ‘a’ o ‘5’ o ‘.’ es el hecho de que usted, como un ser humano que usa sus globos oculares, generalmente no puede mirar una pantalla de texto e identificar o contar los caracteres de las tabs. Visualmente, una secuencia de tabs es idéntica a una secuencia de (un número generalmente mayor pero todavía visualmente indeterminado de) espacios.

Con el fin de representar de forma inequívoca las tabs dentro del texto destinado al procesamiento por computadora, tenemos varios métodos sintácticos para decir “¡Eh, algún software ! Reemplace esta basura con un carácter de pestaña más tarde, ¿vale?”.

En la historia de los lenguajes de progtwigción ha habido dos enfoques principales; Si regresa a la década de 1950, puede lograr que ambos enfoques existan uno al lado del otro, uno en cada uno de los dos idiomas más antiguos de alto nivel. Lisp había nombrado literales de caracteres como #\Tab ; Estos se convirtieron tan pronto como se leyeron de la fuente del progtwig. Fortran solo tenía la función CHAR , que fue llamada en tiempo de ejecución y devolvió el carácter cuyo número coincidía con el argumento: CHAR(9) devolvió una pestaña. (Por supuesto, si fuera realmente CHAR(9) y no CHAR( una expresión que funciona con 9 ) , un comstackdor optimizador podría notar eso y reemplazar la llamada a la función con una pestaña en el momento de la comstackción, devolviéndonos a la otra) acampar.)

En general, con ambos tipos de soluciones, si deseaba pegar el carácter especial dentro de una cadena más grande, tenía que hacer la concatenación usted mismo; por ejemplo, un niño que piratea BASIC en los 80 podría escribir algo como esto:

 10 PRINT "This is a tab ->"; CHR$(9); "<- That was a tab" 

Pero algunos idiomas, especialmente la familia que comenzó con el lenguaje B, introdujeron la capacidad de incluir estos caracteres directamente dentro de una cadena literal:

 printf("This is a tab -> *t <- That was a tab"); 

BCPL conservó la syntax * , pero el siguiente idioma de la serie, C, la reemplazó con la barra invertida, probablemente porque necesitaban leer y escribir asteriscos literales con mucha más frecuencia que las barras invertidas literales.

De todos modos, una gran cantidad de idiomas, incluidos Python y Javascript, han tomado prestadas o heredadas las convenciones de C aquí. Por lo tanto, en ambos idiomas, las dos expresiones "\t" y '\t' dan como resultado una cadena de un solo carácter en la que ese único carácter es una pestaña.

JSON se basa en la syntax de Javascript, pero solo permite un subconjunto restringido de la misma. Por ejemplo, las cadenas deben incluirse entre comillas dobles ( " ) en lugar de simples ( ' ), y no se permiten tabulaciones literales dentro de ellas.

Eso significa que esta cadena Python de tu actualización:

 foo = '{"My_string": "Foo bar.\t Bar foo."}' 

No es válido JSON. El intérprete de Python convierte la secuencia \t en un carácter de tabulación real tan pronto como lee la cadena, mucho antes de que el procesador JSON la vea.

Puedes decirle a Python que coloque un literal \t en la cadena en lugar de un carácter de tabulación doblando la barra invertida:

 foo = '{"My_string": "Foo bar.\\t Bar foo."}' 

O puede usar la syntax de cadena "sin procesar", que no interpreta las secuencias especiales de barra invertida:

 foo = r'{"My_string": "Foo bar.\t Bar foo."}' 

De cualquier manera, el procesador JSON verá una cadena que contiene una barra invertida seguida de una 't', en lugar de una cadena que contiene una pestaña.

Puede incluir tabs dentro de los valores (en lugar de como espacios en blanco) en los archivos JSON al escapar de ellos. Aquí hay un ejemplo de trabajo con el módulo json en Python2.7:

 >>> import json >>> obj = json.loads('{"MY_STRING": "Foo\\tBar"}') >>> obj['MY_STRING'] u'Foo\tBar' >>> print obj['MY_STRING'] Foo Bar 

Si bien no se escapa el '\t' causa un error:

 >>> json.loads('{"MY_STRING": "Foo\tBar"}') Traceback (most recent call last): File "", line 1, in  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 338, in loads return _default_decoder.decode(s) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 365, in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 381, in raw_decode obj, end = self.scan_once(s, idx) ValueError: Invalid control character at: line 1 column 19 (char 18) 

Solo para compartir mi experiencia:

Estoy usando snakemake y un archivo de configuración escrito en Json. Hay tabs en el archivo json para la sangría. TAB son legales para este fin. Pero recibo un mensaje de error: snakemake.exceptions.WorkflowError: el archivo de configuración no es JSON o YAML válido. Creo que esto es un error de Snakemake; Pero podría estar equivocado. Por favor comenta. Después de reemplazar todos los TABs con espacios, el mensaje de error desaparece.

En el nodo rojo, el flujo me enfrenta al mismo tipo de problema:

 flow.set("delimiter",'"\t"'); 

error:

 { "status": "ERROR", "result": "Cannot parse config: String: 1: in value for key 'delimiter': JSON does not allow unescaped tab in quoted strings, use a backslash escape" } 

solución:

He añadido en sólo \\t en el código.

  flow.set("delimiter",'"\\t"');