Cuerdas multilínea en JSON

656

Estoy escribiendo algunos archivos de datos en formato JSON y me gustaría tener algunos valores de cadena realmente largos divididos en varias líneas. Al usar el módulo JSON de Python, obtengo muchos errores, ya sea que lo use \o \ncomo escape.

¿Es posible tener cadenas de varias líneas en JSON? Es principalmente para la comodidad visual, así que supongo que puedo activar el ajuste de texto en mi editor, pero tengo curiosidad ...

Anonnobody
fuente
2
Posible duplicado de ¿Cómo manejo las nuevas líneas en JSON?
Flimzy
1
estructura tus datos: divide la cadena multilínea en una matriz de cadenas y luego únelas más adelante.
RubyTuesdayDONO
2
Prueba la herramienta hjson. Convertirá su cadena multilínea en json al formato json adecuado.
gaurav

Respuestas:

403

JSON no permite saltos de línea reales. Debe reemplazar todos los saltos de línea con \n.

p.ej:

"first line second line"

se puede guardar con:

"first line\nsecond line"

Nota:

para Python, esto debe escribirse como:

"first line\\nsecond line"

donde \\es para escapar de la barra diagonal inversa, de lo contrario, Python tratará \ncomo el carácter de control "nueva línea"


fuente
89
-1 El OP está utilizando la secuencia de escape "\ n". No funciona porque no están escapando de la barra invertida , como "\\ n", por lo que Python está convirtiendo la secuencia de escape en un carácter de nueva línea en lugar de dejarla literalmente como una barra invertida seguida de una en, como requiere JSON.
user359996
66
@ user359996 No estoy seguro de que sea cierto. Para mí (almacenar datos en JSON con solo \ny enviarlos a través de Curses), \nparece funcionar bien. Parece que depende del motor de visualización / renderizado.
cenizas999
2
Las secuencias de nueva línea son de hecho específicas de la plataforma (véase en.wikipedia.org/wiki/Newline#Representations ). Sin embargo, según @Lightness Races en la respuesta de Orbit, ni los caracteres de retorno de cursor ni de avance de línea están en la gramática JSON. En realidad no soy un programador de Python, así que no estoy seguro de lo que está sucediendo en su caso, pero su analizador está roto o no lo está pasando como cree que es. Tal vez esta respuesta lo explique mejor: stackoverflow.com/a/9295597/359996 . Tenga en cuenta especialmente el bit sobre doble escape.
user359996
55
@Nawaz: "\ n" y "\ r" son secuencias de escape para salto de línea y retorno de carro, respectivamente. No son los caracteres de control de salto de línea y retorno de carro literales . Como un ejemplo adicional para hacerlo más claro, considere que "\\" es una secuencia de escape para la barra diagonal inversa, en lugar de una barra diagonal inversa. La gramática JSON excluye explícitamente los caracteres de control (véase la definición "char") y, en cambio, proporciona su representación a través de secuencias de escape (\\, \ r, \ n, etc.).
user359996
2
@ user359996: Sí. Vi eso más tarde, aunque mantengo mi antiguo comentario como tal, en caso de que alguien más tenga la misma duda, nuestra discusión podría ayudarlos. gracias por confirmarlo BTW.
Nawaz
197

Tuve que hacer esto para un pequeño proyecto Node.js y encontré esta solución :

{
 "modify_head": [

  "<script type='text/javascript'>",
  "<!--",
  "  function drawSomeText(id) {",
  "  var pjs = Processing.getInstanceById(id);",
  "  var text = document.getElementById('inputtext').value;",
  "  pjs.drawText(text);}",
  "-->",
  "</script>"

 ],

 "modify_body": [

  "<input type='text' id='inputtext'></input>",
  "<button onclick=drawSomeText('ExampleCanvas')></button>"

 ],
}

Esto se ve bastante bien para mí, además de que tengo que usar comillas dobles en todas partes. Aunque de lo contrario, podría, quizás, usar YAML, pero eso tiene otras dificultades y no es compatible de forma nativa. Una vez analizado, solo uso myData.modify_head.join('\n')o myData.modify_head.join(), dependiendo de si quiero un salto de línea después de cada cadena o no.

desarrollador de errores
fuente
40
Esta es una solución para un entorno específico, no necesariamente relacionado con la pregunta. Lo que crea allí no son cadenas multilínea (que de todos modos no es posible), sino matrices con cadenas dentro
Samuel Rivas
3
Esto muestra cómo insertar nueva línea en cadenas, que NO responde la pregunta. Esta respuesta lo hace.
fgrieu
1
fgrieu: uno podría concatenar fácilmente las cadenas sin agregar una nueva línea. Con esa pequeña alteración, proporciona una solución alternativa para cadenas multilínea (siempre y cuando tenga el control de especificar el esquema JSON). Trataré de mejorar la respuesta con esto.
drrob
1
Gracias me gusta esto Voy con esto por lo que estoy trabajando. Se ve ordenado y organizado. Voy a tener que cada nueva línea en esta matriz implique un salto de línea en el texto de salida, aunque esta solución también podría funcionar para casos en los que no inserte saltos de línea. He usado esta solución antes en mi código fuente de JavaScript solo porque me gustó lo organizada que se ve y cómo no deja ninguna duda sobre qué tipos de espacios en blanco entran en la cadena final.
Gal
A pesar de las reservas del inventor de JSON, solo utilicé esto para agregar comentarios (sin la parte de JavaScript, pero solo las [] y las comas) para agregar comentarios para ayudar a un posible futuro mantenedor que podría editar manualmente mi pequeño archivo JSON.
Whirl Mind
117

Desafortunadamente, muchas de las respuestas aquí abordan la pregunta de cómo poner un carácter de nueva línea en los datos de la cadena. La pregunta es cómo hacer que el código se vea mejor dividiendo el valor de la cadena en varias líneas de código. (E incluso las respuestas que reconocen esto proporcionan "soluciones" que suponen que uno es libre de cambiar la representación de datos, que en muchos casos no lo es).

Y la peor noticia es que no hay una buena respuesta.

En muchos lenguajes de programación, incluso si no admiten explícitamente la división de cadenas entre líneas, aún puede usar la concatenación de cadenas para obtener el efecto deseado; y mientras el compilador no sea horrible, está bien.

Pero json no es un lenguaje de programación; Es solo una representación de datos. No se puede decir que concatene cadenas. Su gramática (bastante pequeña) tampoco incluye ninguna facilidad para representar una cadena en varias líneas.

Si no diseñamos un preprocesador de algún tipo (y yo, por mi parte, no tengo ganas de inventar mi propio idioma para resolver este problema), no hay una solución general para este problema. SI puede cambiar el formato de datos, puede sustituir una serie de cadenas. De lo contrario, esta es una de las numerosas formas en que json no está diseñado para la legibilidad humana.

Mark Adelsberger
fuente
3
No está claro lo que quiere el OP, las nuevas líneas en la cadena, u organizar mejor la cadena ...
9ilsdx 9rvj 0lo
3
@ 9ilsdx9rvj0lo: No, no lo es.
Mark Adelsberger
Con respecto a "La pregunta es cómo hacer que el código se vea mejor dividiendo el valor de la cadena en varias líneas de código ...": para una solución a las declaraciones de varias líneas en Python, consulte stackoverflow.com/questions/53162/… . Hay una diferencia entre JSON multilínea y Python multilínea. El uso de JSON multilínea '\' seguido de 'n' en el JSON, es decir, "\ n" en la cadena. Enunciados de Python de varias líneas, use '\' seguido de '\ n', es decir, una barra diagonal inversa en la línea que se continuará. Formato de Windows: reemplace \ n con \ r \ n donde corresponda.
Ivan
106

¡Mira la especificación ! La gramática de JSON carbón de producción puede tomar los siguientes valores:

  • any-Unicode-character-except- "-or- \-or-control-character
  • \"
  • \\
  • \/
  • \b
  • \f
  • \n
  • \r
  • \t
  • \u cuatro dígitos hexadecimales

Las nuevas líneas son "caracteres de control", así que no, es posible que no tenga una nueva línea literal dentro de su cadena. Sin embargo, puede codificarlo usando cualquier combinación de \ny \rque necesite.

Carreras de ligereza en órbita
fuente
3
Esta es la respuesta correcta, ya que no deja ambigüedad. Se permiten nuevas líneas , según las especificaciones, siempre que se escapen correctamente con el carácter de control.
Ryan
@AliKhaki \ n en JSON no logrará el resultado buscado por la pregunta. O está pensando en otra cosa (es decir, incrustando caracteres de nueva línea), o está hablando de una nueva línea en un literal de cadena (que contiene JSON) en algún lenguaje de programación, que nuevamente es algo diferente.
ligereza corre en órbita el
@LightnessRacesinOrbit sí, estoy buscando una nueva línea en cadena
Ali Khaki
46

JSON no permite líneas de corte para facilitar la lectura.

Su mejor opción es usar un IDE que se ajuste a la línea por usted.

James Gentes
fuente
1
Un editor como BBEdit que admita el ajuste de línea "suave" es ideal. Envuelve el texto para que todo aparezca dentro del área visible de la ventana del editor, pero solo las terminaciones de línea que escribe (por ejemplo, presionar el retorno de carro) persisten en el archivo cuando se guarda. Facilita la edición de JSON con cadenas realmente largas sin tener que recurrir a trucos o hacks de código.
cshotton
44

Esta es una pregunta muy antigua, pero me encontré con esto en una búsqueda y creo que conozco la fuente de su problema.

JSON no permite nuevas líneas "reales" en sus datos; solo puede haber escapado de nuevas líneas. Vea la respuesta de @YOU . Según la pregunta, parece que intentaste escapar de los saltos de línea en Python de dos maneras: usando el carácter de continuación de línea ( "\") o "\n"como un escape.

Pero tenga en cuenta: si está utilizando una cadena en python, los caracteres escapados especiales ( "\t", "\n") se traducen en caracteres de control REAL. El "\n"será reemplazado con el carácter de control ASCII que representa un carácter de nueva línea, que es precisamente el carácter que es ilegal en JSON. (En cuanto al carácter de continuación de línea, simplemente elimina la nueva línea).

Entonces, lo que debe hacer es evitar que Python escape de los caracteres. Puede hacer esto usando una cadena sin procesar (colocada rdelante de la cadena, como en r"abc\ndef", o incluyendo una barra adicional delante de la nueva línea ( "abc\\ndef").

Ambos de los anteriores, en lugar de reemplazar "\n"con el carácter de control ASCII de nueva línea real, dejarán "\n"como dos caracteres literales, que luego JSON puede interpretar como un escape de nueva línea.

HardlyKnowEm
fuente
12

Escriba el valor de la propiedad como una matriz de cadenas. Como ejemplo dado aquí https://gun.io/blog/multi-line-strings-in-json/ . Esto ayudará.

Siempre podemos usar una matriz de cadenas para cadenas multilínea como las siguientes.

{
    "singleLine": "Some singleline String",
    "multiline": ["Line one", "line Two", "Line Three"]
} 

Y podemos iterar fácilmente la matriz para mostrar contenido en varias líneas.

Sandip Nirmal
fuente
1
Le sugiero que agregue la información en su respuesta desde el enlace, porque los enlaces pueden romperse en el futuro.
YoungHobbit
55
Pero para ellos tienes una matriz, no una cadena. Una matriz no es una cadena. Período.
9ilsdx 9rvj 0lo
Solo estaba pensando en esto. ¡Agradable!
Phillip Jacobs
12

Use json5 (cargador) vea https://json5.org/ - ejemplo (por json5)

{
  lineBreaks: "Look, Mom! \
No \\n's!",
}
Lacom
fuente
La pregunta que hizo el OP. Al menos si puede usar json5.
nomen
10

¿Es posible tener cadenas de varias líneas en JSON?

Si. Acabo de probar esto ahora con mi navegador web Firefox presionando F12, haciendo clic en la consola y escribiendo en la parte inferior de la pantalla.

x={text:"hello\nworld"}

El objeto x acaba de crearse a partir de una cadena de formato JSON que contiene una cadena de varias líneas.

console.log(x.text)
hello
world

x.text se muestra mostrando que es una cadena de varias líneas.

Estas dos pruebas muestran que el intérprete Javascript de Firefox se complace en crear y usar JSON con cadenas multilínea.

Más pruebas con JSON.stringifyy JSON.parsedemostraron que el intérprete Javascript puede convertir un objeto que contiene cadenas multilínea a JSON y analizarlo nuevamente sin ningún problema.

En el pasado, almacené los trabajos completos de Shakespeare como una propiedad en un objeto JSON y luego los envié a través de Internet, sin corrupción.

Ejemplo

Aquí hay una cadena de dos líneas ingresada en tres líneas

x={text:"expert\
s\nex\
change"}

Podemos mostrar el objeto

console.log(x)

dando

Object { text: "experts\nexchange" }

o la cuerda

console.log(x.text)

dando

experts
exchange

El final de las líneas en la cadena resulta del uso de \ n y las múltiples líneas de entrada se logran usando solo \ al final de la línea.

En la práctica, es posible que desee sincronizar las terminaciones de línea con las de la cadena, p. Ej.

x={text:"experts\n\
exchange"}

Longitud de cadena de varias líneas

console.log("Hello\nWorld".length)
11 
console.log("Hello World".length)
11

Tenga en cuenta que la cadena con la nueva línea no es más larga que la cadena con el espacio. Aunque se escribieron dos caracteres en el teclado ('\' y 'n'), solo se almacena un carácter en la cadena.

Ivan
fuente
3
Un lector de formato de cadena de JavaScript no es un lector de formato de cadena JSON y viceversa, por lo que si bien funciona, la consola de JavaScript también acepta x={"a":NaN}y x={"a":"a \<literal newline with SHIFT>b"}, que no son JSON, pero son JavaScript
cat
9

Use regex para reemplazar todas las apariciones de \r\ncon \\n.

Esto funcionó para mí en scala.

val newstr = str.replace("\r\n", "\\n")
Sikander
fuente
¿Por qué las 3 barras invertidas?
neXus
66
@neXus No sé por qué, pero alguien lo editó en 3 barras diagonales inversas. Gracias a LightnessRacesInOrbit por corregirlo.
Sikander
5

Si está dispuesto a usar Node.js, puede hacer esto:

module.exports = {

  multilineStr: `

     dis my life 
     it's now or never

  `

}

puede importar con Node.js y convertirlo a JSON fácilmente así:

echo `node -pe 'JSON.stringify(require("./json-mod.js"))'`

y obtienes:

{"multilineStr":"\n \n dis my life\n it's now or never\n \n "}

cómo funciona : usa Node.js para cargar un módulo JS, que crea un objeto JS que puede ser fácilmente JSON stringified por Node.js. La opción -e evalúa la cadena, y la -popción hace eco del resultado de retorno de la última operación Node.js en stdout.

Si desea cargar un script .js que está en un directorio de trabajo diferente, debe cambiar las cadenas "" y '':

my_script='../json-mod.js'
echo `node -pe "JSON.stringify(require('$my_script'))"`
Alexander Mills
fuente
-4

Intente usar un base64valor de cadena codificado. Trabajó para mí la mayor parte del tiempo.

{
    "singleLine": "Some singleline String",
    "multiline": ["Line one", "line Two", "Line Three"]
} 

después de que la base64cadena codificada se vea como

{
    "singleLine": "Some singleline String",
    "multiline": "TGluZSBvbmUKTGluZSBUd28KTGluZSBUaHJlZQ=="
} 

La codificación y decodificación base64 está disponible en todos los idiomas.

Sunit Parekh
fuente
77
Necesita un código especial para mostrarlo, está transformando una cadena en una matriz. No es una solución
tom10271
3
Creo que es una mala idea: oscurece el contenido innecesariamente y requiere código, tiempo, memoria y herramientas adicionales para producirlo y consumirlo. Escanear a través de la cadena y reemplazar caracteres especiales, por supuesto, también requiere código adicional, tiempo y memoria, pero definitivamente menos que la codificación y decodificación base64
Semanino
Esta es una mala idea porque la legibilidad del JSON se ha ido, y también como @ tom10271 mencionó, necesita una operación adicional para usar el json
T90
-23

poner el texto multilínea en el archivo txt y luego

var str = {
    text: cat('path_to_file/text.txt')
}

(funciona en mongoDB)

flaalf
fuente
11
-1: esta es una respuesta engañosa. No es JSON válido ni funciona en JavaScript, ya que no hay una función nombrada cat.
Martin Schuhfuß