Convertir cadena de objeto a JSON

165

¿Cómo puedo convertir una cadena que describe un objeto en una cadena JSON usando JavaScript (o jQuery)?

por ejemplo: Convertir esto ( NO una cadena JSON válida):

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }"

dentro de esto:

str = '{ "hello": "world", "places": ["Africa", "America", "Asia", "Australia"] }'

Me encantaría evitar usar eval()si es posible.

snorpey
fuente
¿Por qué su cadena no es JSON válida en primer lugar? ¿Cómo estás generando eso?
Rocket Hazmat
2
La cadena se almacena en un dataatributo, como este: <div data-object="{hello:'world'}"></div>y no quiero usar comillas simples en el HTML (por lo que probablemente no sea de confianza)
snorpey
55
@snorpey: <div data-object='{"hello":"world"}'></div>es HTML 100% válido (¿qué tienen que ver las comillas simples con confiar en él o no?). Si lo hace de esta manera, puede JSON.parsehacerlo y funcionará bien. Nota: las claves también deben ser citadas.
Rocket Hazmat
@Rocket gracias por tus esfuerzos! Solo quería encontrar una forma de evitar el uso de comillas simples en HTML (a pesar de que es 100% válido) y la notación JSON.
snorpey
@snorpey: en primer lugar, no es poner JSON en un atributo HTML. Supongo que podrías usar comillas dobles y escapar de las del JSON <div data-object="{\"hello\":\"world\"}"></div>. Si no desea utilizar un JSON válido en el atributo, deberá crear su propio formato y analizarlo usted mismo.
Rocket Hazmat

Respuestas:

181

Si la cadena es de una fuente confiable , podría utilizar evalentonces JSON.stringifyel resultado. Me gusta esto:

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";
var json = JSON.stringify(eval("(" + str + ")"));

Tenga en cuenta que cuando se evaltrata de un objeto literal, debe estar entre paréntesis, de lo contrario, las llaves se analizan como un bloque en lugar de un objeto.

También estoy de acuerdo con los comentarios bajo la pregunta de que sería mucho mejor codificar el objeto en un JSON válido para comenzar y evitar tener que analizar, codificar y luego presumiblemente analizarlo nuevamente . HTML admite atributos con comillas simples (solo asegúrese de codificar en HTML las comillas simples dentro de las cadenas).

Matthew Crumley
fuente
esto no tiene sentido, si la cadena es de fuente confiable, por qué la convertimos en su lugar, la hacemos como json válida.
allenhwkim
2
@allenhwkim La idea es convertir de JSON no válido a JSON válido, por lo que evalconvierte la cadena en un objeto JavaScript (que funciona, siempre que la cadena represente JavaScript válido, incluso si no es JSON válido). Luego JSON.stringifyconvierte de un objeto a una cadena JSON (válida). Las llamadas evalson peligrosas si la cadena no proviene de una fuente confiable porque literalmente podría ejecutar cualquier JavaScript que abre la posibilidad de ataques de secuencias de comandos entre sitios.
Matthew Crumley
2
eval seguirá haciendo cosas malas en este caso si la cadena se construye, por ejemplo, así: var str = "(function () {console.log (\" bad \ ")}) ()";
Rondo
El uso de eval () ejecutará el código JS. Puede ser abusado fácilmente.
FisNaN
@allenhwkim: nunca confiamos en ninguna fuente. Confiar en TI significa verificar, verificar y verificar nuevamente.
Laszlo Varga
110

Su cadena no es válida JSON, por lo que JSON.parse(o jQuery $.parseJSON) no funcionará.

Una forma sería usarlo evalpara "analizar" el JSON "inválido" y luego stringify"convertirlo" en JSON válido.

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }"
str = JSON.stringify(eval('('+str+')'));

Sugiero que, en lugar de intentar "arreglar" su JSON no válido, comience con un JSON válido en primer lugar. Cómo se strgenera, debe fijarse allí, antes de que se genere, no después.

EDITAR : Usted dijo (en los comentarios) que esta cadena se almacena en un atributo de datos:

<div data-object="{hello:'world'}"></div>

Sugiero que lo arregles aquí, para que pueda ser JSON.parsed. Primero, tanto las claves como los valores deben ser entre comillas dobles. Debería verse así (los atributos con comillas simples en HTML son válidos):

<div data-object='{"hello":"world"}'></div>

Ahora, solo puede usar JSON.parse(o jQuery's $.parseJSON).

var str = '{"hello":"world"}';
var obj = JSON.parse(str);
Cohete Hazmat
fuente
49

jQuery.parseJSON

str = jQuery.parseJSON(str)

Editar. Esto se proporciona si tiene una cadena JSON válida

Farmor
fuente
1
cierto, vi la pregunta de cómo convertir una cadena JSON a un objeto
Farmor
43

Use un código simple en el siguiente enlace:

http://msdn.microsoft.com/es-es/library/ie/cc836466%28v=vs.94%29.aspx

var jsontext = '{"firstname":"Jesper","surname":"Aaberg","phone":["555-0100","555-0120"]}';
var contact = JSON.parse(jsontext);

y revertir

var str = JSON.stringify(arr);
Ronald
fuente
Convertir jsontext en un objeto String a través de un nuevo String (jsontext) probablemente sea aún mejor, por seguridad de tipo.
Fuzzy Analysis
@fuzzyanalysis: No, nunca se deben usar envoltorios primitivos.
Ry-
1
JSON.parse () debería ser la respuesta aceptada aquí según lo indicado por @LouiseMcMahon
pixel 67 el
24

Espero que esta pequeña función convierta una cadena JSON no válida en una válida.

function JSONize(str) {
  return str
    // wrap keys without quote with valid double quote
    .replace(/([\$\w]+)\s*:/g, function(_, $1){return '"'+$1+'":'})    
    // replacing single quote wrapped ones to double quote 
    .replace(/'([^']+)'/g, function(_, $1){return '"'+$1+'"'})         
}

Resultado

var invalidJSON = "{ hello: 'world',foo:1,  bar  : '2', foo1: 1, _bar : 2, $2: 3, 'xxx': 5, \"fuz\": 4, places: ['Africa', 'America', 'Asia', 'Australia'] }"
JSON.parse(invalidJSON) 
//Result: Uncaught SyntaxError: Unexpected token h VM1058:2
JSON.parse(JSONize(invalidJSON)) 
//Result: Object {hello: "world", foo: 1, bar: "2", foo1: 1, _bar: 2…}
allenhwkim
fuente
Estamos tratando de eliminar la evaluación de b usando JSON. Analizar nuestro código y esto parece una buena solución. Todavía tendremos que manejar el reemplazo constante a mano, pero al menos esto permite contener esos casos.
ravemir
1
Es casi perfecto No funciona cuando : está en uno de los valores.
seler
9

Usar con precaución (por eval()):

function strToJson(str) {
  eval("var x = " + str + ";");
  return JSON.stringify(x);
}

llamar como:

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";
alert( strToJson(str) );
Tomalak
fuente
3
Al votante anónimo abajo. Te reto a que proporciones una mejor solución. Aparte de eso, una razón para el voto negativo sería buena.
Tomalak
1
@Rocket: Estás equivocado. a) eval()es la única forma de hacerlo. b) Advertí al OP al respecto. c) Mira la respuesta de Matthew Crumley y piensa en una mejor explicación. (Ah, yd) la afirmación eval()es mala no tiene sentido en esta forma generalizada.)
Tomalak
2
@Rocket: Ah, malentendido allí mismo. Lo siento, pensé que el voto negativo era tuyo. :)
Tomalak
1
@kuboslav: Funciona bien, ¿incluso lo probaste? Él está haciendo lo eval("var x = " + str + ";")que es totalmente válido JS. No necesitas hacer var x = ({a:12}).
Rocket Hazmat
2
@kuboslav No funciona en IE7 porque IE7 no tiene soporte JSON nativo. Comenzará a funcionar tan pronto como lo use json2.js. No seas tan feliz como un gatillo.
Tomalak
4

Descargo de responsabilidad: no intentes esto en casa, o para cualquier cosa que requiera que otros desarrolladores te tomen en serio:

JSON.stringify(eval('(' + str + ')'));

Ahí lo hice.
Intenta no hacerlo aunque eval sea MALO para ti. Como se indicó anteriormente, use la cuña JSON de Crockford para navegadores más antiguos (IE7 y menos)

Este método requiere que su cadena sea javascript válido , que se convertirá en un objeto javascript que luego se puede serializar a JSON.

editar: arreglado como Rocket sugirió.

gonchuki
fuente
Debería ser JSON.stringify(eval('('+str+')'));, no es que lo apruebe eval, pero su cadena no es JSON válida, por lo JSON.parseque no funciona.
Rocket Hazmat
4

Puse mi respuesta para alguien que esté interesado en este viejo hilo.

He creado el HTML 5 * Data-analizador para jQuery plugin y de demostración que convierten una cadena JSON mal formado en un objeto sin necesidad de utilizar JavaScript eval().

Puede pasar los atributos de datos HTML5 * a continuación:

<div data-object='{"hello":"world"}'></div>
<div data-object="{hello:'world'}"></div>
<div data-object="hello:world"></div>

en el objeto:

{
    hello: "world"
}
tokkonopapa
fuente
2

Hay una manera mucho más simple de lograr esta hazaña, solo secuestra el atributo onclick de un elemento ficticio para forzar el retorno de su cadena como un objeto JavaScript:

var jsonify = (function(div){
  return function(json){
    div.setAttribute('onclick', 'this.__json__ = ' + json);
    div.click();
    return div.__json__;
  }
})(document.createElement('div'));

// Let's say you had a string like '{ one: 1 }' (malformed, a key without quotes)
// jsonify('{ one: 1 }') will output a good ol' JS object ;)

Aquí hay una demostración: http://codepen.io/csuwldcat/pen/dfzsu (abra su consola)

csuwldcat
fuente
2

Debe usar "eval", luego JSON.stringify y luego JSON.parse al resultado.

 var errorString= "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";
 var jsonValidString = JSON.stringify(eval("(" + errorString+ ")"));
 var JSONObj=JSON.parse(jsonValidString);

ingrese la descripción de la imagen aquí

Negi Rox
fuente
1

Debe escribir corchetes, porque sin ellos evalconsiderará el código dentro de los corchetes como bloque de comandos.

var i = eval("({ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] })");
kuboslav
fuente
1

Su mejor y más segura apuesta sería JSON5 - JSON para humanos . Está creado específicamente para ese caso de uso.

const result = JSON5.parse("{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }");

console.log(JSON.stringify(result));
<script src="https://cdnjs.cloudflare.com/ajax/libs/json5/0.5.1/json5.min.js"></script>

dereli
fuente
1

Usar la nueva función () es mejor que evaluar, pero aún así solo debe usarse con una entrada segura.

const parseJSON = obj => Function('"use strict";return (' + obj + ')')();

console.log(parseJSON("{a:(4-1), b:function(){}, c:new Date()}"))
// outputs: Object { a: 3, b: b(), c: Date 2019-06-05T09:55:11.777Z }

Fuentes: MDN , 2ality

SamGoody
fuente
0

Para su ejemplo simple anterior, puede hacer esto usando 2 reemplazos regex simples:

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";
str.replace(/(\w+):/g, '"$1":').replace(/'/g, '"');
 => '{ "hello": "world", "places": ["Africa", "America", "Asia", "Australia"] }'

Gran advertencia : este enfoque ingenuo supone que el objeto no tiene cadenas que contengan un carácter 'o :. Por ejemplo, no puedo pensar en una buena manera de convertir la siguiente cadena de objetos a JSON sin usar eval:

"{ hello: 'world', places: [\"America: The Progressive's Nightmare\"] }"
Topher Hunt
fuente
0

Solo por las peculiaridades de esto, puedes convertir tu cadena a través de babel-standalone

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";

function toJSON() {
  return {
    visitor: {
      Identifier(path) {
        path.node.name = '"' + path.node.name + '"'
      },
      StringLiteral(path) {
        delete path.node.extra
      }
    }
  }
}
Babel.registerPlugin('toJSON', toJSON);
var parsed = Babel.transform('(' + str + ')', {
  plugins: ['toJSON']
});
var json = parsed.code.slice(1, -2)
console.log(JSON.parse(json))
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

Moritz Roessler
fuente
0

var str = "{hola: 'mundo', lugares: ['África', 'América', 'Asia', 'Australia']}" var fStr = str .replace (/ ([Az] *) (:) / g, '"$ 1":') .replace (/ '/ g, "\" ")

console.log (JSON.parse (fStr))ingrese la descripción de la imagen aquí

Lo siento, estoy en mi teléfono, aquí hay una foto.

Francis Leigh
fuente
0

Una solución con una expresión regular y sin usar eval:

str.replace(/([\s\S]*?)(')(.+?)(')([\s\S]*?)/g, "$1\"$3\"$5")

Creo que esto debería funcionar para varias líneas y todas las posibles ocurrencias (/ g flag) de 'string' entre comillas simples reemplazadas por "string" entre comillas dobles.

Chaitanya P
fuente
0
var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";
var json = JSON.stringify(eval("(" + str + ")"));
praveenkumar
fuente
-1

Quizás tengas que probar esto:

str = jQuery.parseJSON(str)
howdyhyber
fuente
La pregunta especificó "o jQuery" y esta es la solución perfecta si la tiene disponible.
Ecropolis