javascript - ¿JSON.stringify sin comillas en las propiedades?
Estoy usando un servicio que utiliza un formato JSON incorrecto (sin comillas dobles alrededor de las propiedades). Así que necesito enviar
{ name: "John Smith" } en lugar de { "name": "John Smith" }
Este formato no se puede cambiar ya que este no es mi servicio.
¿Alguien conoce una forma de stringify routing para formatear un objeto de JavaScript como el de arriba?
Respuesta #1
Esta simple solución con expresiones regulares funciona para descomillar los nombres de propiedades JSON en la mayoría de los casos:
const object = { name: 'John Smith' };
const json = JSON.stringify(object); // {"name":"John Smith"}
console.log(json);
const unquoted = json.replace(/"([^"]+)":/g, '$1:');
console.log(unquoted); // {name:"John Smith"}Caso extremo:
var json = '{ "name": "J\\":ohn Smith" }'
json.replace(/\\"/g,"\uFFFF"); // U+ FFFF
json = json.replace(/"([^"]+)":/g, '$1:').replace(/\uFFFF/g, '""');
// '{ name: "J\":ohn Smith" }'
Un agradecimiento especial a Rob W por arreglarlo.
Limitaciones
En casos normales, la expresión regular mencionada funcionará, pero matemáticamente es imposible describir el formato JSON con una expresión regular de manera que funcione en todos y cada uno de los casos (contar el mismo número de llaves es imposible con una expresión regular). Por lo tanto, he creado una nueva función para eliminar las comillas analizando formalmente la cadena JSON mediante la función nativa y resserializándola:
function stringify(obj_from_json) {
if (typeof obj_from_json !== "object" || Array.isArray(obj_from_json)){
// not an object, stringify using native function
return JSON.stringify(obj_from_json);
}
// Implements recursive object serialization according to JSON spec
// but without quotes around the keys.
let props = Object
.keys(obj_from_json)
.map(key => `${key}:${stringify(obj_from_json[key])}`)
.join(",");
return `{${props}}`;
}
Ejemplo: https://jsfiddle.net/DerekL/mssybp3k/
Respuesta #2
Parece que esto es un simple método toString de Object que estás buscando.
En Node.js esto se resuelve usando el objeto util y llamando a util.inspect(tuObjeto). Esto te dará todo lo que deseas. sigue este enlace para más opciones, incluyendo la profundidad de la aplicación del método. http://nodejs.org/api/util.html#util_util_inspect_object_options
Entonces, lo que estás buscando es básicamente un inspector de objetos, no un convertidor de JSON. El formato JSON especifica que todas las propiedades deben estar entre comillas dobles. Por lo tanto, no habrá convertidores de JSON para hacer lo que deseas, ya que eso simplemente no es un formato JSON. Especificaciones aquí: https://developer.mozilla.org/en-US/docs/Using_native_JSON
Convertir un objeto a cadena o inspección es lo que necesitas dependiendo del lenguaje de tu servidor.
Respuesta #3
TL;DR -- El Código
Con una advertencia, a continuación, sobre el soporte de lookbehind en los navegadores, aquí tienes:
function cleanIt(obj) {
var cleaned = JSON.stringify(obj, null, 2);
return cleaned.replace(/^[\t ]*"[^:\n\r]+(?<!\\)":/gm, function (match) {
return match.replace(/"/g, "");
});
}
NOTA: Los lookbehinds no son compatibles con IE o, curiosamente, ninguna versión de Safari a partir del 18 de junio de 2021. Para usarlos allí, elimine
(?<!\\)de la expresión regular y tenga cuidado con la condición "complicación" mencionada a continuación.
Eso se convierte en cadena con belleza, usa nuestra expresión regular para encontrar claves, luego cada coincidencia de clave se reemplaza mediante una función de reemplazo que dice "aquí está tu coincidencia con todas las comillas dobles eliminadas". Dado que solo hicimos coincidir las claves hasta sus dos puntos, eso es exactamente lo que queremos.
Descripción detallada a continuación.
Por qué la respuesta aceptada no está bien
Desafortunadamente, como señala Adel, hay un problema bastante serio con la solución de Derek sin expresiones regulares. No maneja arreglos de objetos. ¿Ves cómo se detiene y dice: "Si es un arreglo, deja que JSON.stringify lo maneje"? Eso está bien para tipos de valores simples, pero no para objetos.
// \/\/\/ OH NOES!!! \/\/\/
if (typeof obj_from_json !== "object" || Array.isArray(obj_from_json)){
// not an object, stringify using native function
return JSON.stringify(obj_from_json);
// ^^^^^^^^^^^^^^ No! Don't do that!
}
Edité su fiddle con un caso de fallo. Aquí está la carga útil:
var obj = {
name: "John Smith",
favoriteObjects: [
{ b: "there's", c: "always", d: "something" },
[1, 2, "spam", { f: "hello" }],
{ vowels: "are missing" },
],
favoriteFruits: ["Apple", "Banana"],
};
Y aquí está la salida con espacios en blanco:
{
name:"John Smith",
favoriteObjects:[
{
"b":"there's", <<< Major
"c":"always", <<< fails
"d":"something" <<< here
},
[
1,2,"spam",
{
"f":"hello" <<< and here.
}
],
{
"vowels":"are missing" <<< again.
}
],
favoriteFruits:["Apple","Banana"] <<< that worked!
}
¿Ves? Aunque el arreglo de cadenas (favoriteFruits) funciona, todavía tenemos las comillas en el segundo nivel de serialización para objetos en arreglos (como favoriteObjects). Malo.
Una solución simple
Pasé demasiiiado tiempo tratando de limpiar esa función antes de dar con un truco ingenioso para reducir considerablemente la complejidad del problema, lo que creo que vuelve a meter las expresiones regulares en la mezcla.
Vamos a stringify con espacios en blanco
En la línea del Sr. McGuire, solo quiero decirte una palabra, solo una palabra:
Espacio en blanco.
Vamos a JSON.stringify con algunos espacios en blanco. Eso hace que la expresión regular para eliminar las comillas de las claves sea MUCHO más fácil.
Comienza tu solución con esto:
var cleaned = JSON.stringify(x, null, 2);
La llamada a stringify dice "stringify x (el primer parámetro) sin una función reemplazadora elegante (indicada por el segundo parámetro como null) con dos (tercer parámetro 2) espacios de espacio en blanco para cada nivel de profundidad en la serialización." Ese 2 también nos proporciona líneas separadas para cada propiedad.
{
"name": "John Smith",
"favoriteObjects": [
{
"b": "there's",
"c": "always",
// etc...
Cada tecla ahora está agradablemente al inicio de una línea. Eso podemos manejar.
AHORA limpia las comillas de las teclas
Vamos a crear una expresión regular que busque claves, y solo claves, y elimine sus " circundantes. Dado que sabemos que las claves ahora están todas en sus propias líneas, las cosas son mucho más sencillas.
El único verdadero problema es si el valor de una propiedad contiene ": a mitad de camino. Eso puede complicar las cosas.
"a": [
"This could \": be bad",
"QQ"
]
Advertencia de retroceso
Quería resolver esto con un elegante look-ahead negativo para navegadores antiguos, pero desistí y usé un lookbehind negativo. El lookbehind negativo solo es compatible con un subconjunto de navegadores después de 2018 (descripción de la historia de la propuesta de lookbehind en 2ality aquí, la compatibilidad con navegadores se puede encontrar aquí).
Explicación de RegEx:
/^[\t ]*"[^:\n\r]+(?<!\\)":/gm
Ese regex...
Es una expresión regular
- Empieza con
/
- Empieza con
Busca cualquier línea que comience con (0 a infinito espacios o tabulaciones)
^[\t ]*
Luego un "
"
Luego uno o más caracteres de cualquier cosa que NO SEA un : o un carácter de nueva línea
[^:\n\r]+
Entonces eso termina con los dos caracteres ": que (advertencia de búsqueda inversa negativa) no están precedidos por una barra invertida
(?<!\\)":
Hace esto de manera global y multínea (línea por línea)
/gm
Violín de éxito razonable.
Resultado :
{
name: "John Smith",
favoriteObjects: [
{
b: "there's",
c: "always",
d: "something"
},
[
1,
2,
"spam",
{
f: "hello"
}
],
{
vowels: "are missing"
}
],
favoriteFruits: [
"Apple",
"Banana"
]
}
QED, apenas ocho años y medio después de que jadent preguntara. ¡Eso sí que es servicio!
Actualización Rápida: Una respuesta aún mejor, si no necesariamente necesitas que esto ocurra en código (aunque en algunos casos de uso, también podrías llamar a esta biblioteca directamente), podría ser usar prettier, que limpia las cosas de manera hermosa.
Respuesta #4
Usa JSON5.stringify
JSON5 es un superconjunto de JSON que permite la sintaxis ES5, incluyendo claves de propiedad sin comillas. La implementación de referencia de JSON5 (paquete npm json5) proporciona un objeto JSON5 que tiene los mismos métodos con los mismos argumentos y semántica que el objeto JSON incorporado.
Es muy probable que el servicio que estás utilizando esté usando esta biblioteca. De hecho, JSON5 es utilizado por muchos proyectos de alto perfil:
JSON5 se inició en 2012, y a partir de 2022, ahora recibe más de 65 millones de descargas por semana, se encuentra entre el 0,1% superior de los paquetes más dependientes en npm, y ha sido adoptado por proyectos importantes como Chromium, Next.js, Babel, Retool, WebStorm y más. También es compatible de forma nativa en plataformas de Apple como MacOS e iOS.
~ página principal de json5.org
