Converter sequência de objetos em JSON


165

Como converter uma string que descreve um objeto em uma string JSON usando JavaScript (ou jQuery)?

por exemplo: Converta isso ( NÃO é uma string JSON válida):

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

nisso:

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

Eu adoraria evitar o uso, eval()se possível.


Por que sua string não é JSON válida em primeiro lugar? Como você está gerando isso?
Rocket Hazmat

2
A cadeia de caracteres é armazenado em um data-attrubute, como este: <div data-object="{hello:'world'}"></div>e eu não quero usar aspas simples no HTML (por isso provavelmente não é para ser confiável)
snorpey

5
@ snorpey: <div data-object='{"hello":"world"}'></div>é 100% HTML válido (o que aspas simples têm a ver com confiar ou não?). Se você fizer dessa maneira, poderá JSON.parsefazê-lo e funcionará bem. Nota: as chaves também precisam ser citadas.
Rocket Hazmat

@Rocket Obrigado por seus esforços! Eu só queria encontrar uma maneira de contornar o uso de aspas simples em HTML (mesmo que seja 100% válido) e da notação JSON.
snorpey

@snorpey: O caminho é não colocar JSON em um atributo HTML em primeiro lugar. Eu acho que você pode usar aspas duplas e escapar das do JSON <div data-object="{\"hello\":\"world\"}"></div>. Se você não quiser usar JSON válido no atributo, precisará criar seu próprio formato e analisá-lo.
Rocket Hazmat

Respostas:


181

Se a string é de uma fonte confiável , você pode usar evalentão JSON.stringifyo resultado. Como isso:

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

Observe que, quando evalum objeto é literal, ele deve ser colocado entre parênteses, caso contrário, as chaves são analisadas como um bloco em vez de um objeto.

Também concordo com os comentários da pergunta de que seria muito melhor codificar o objeto no JSON válido para começar e evitar a necessidade de analisar, codificar e, presumivelmente, analisá-lo novamente . O HTML oferece suporte a atributos de aspas simples (apenas codifique HTML quaisquer aspas simples dentro de strings).


isso não faz sentido, se a string é de uma fonte confiável, por que a convertemos em vez de a tornarmos como json válido.
allenhwkim

2
@allenhwkim A idéia é converter de JSON inválido para JSON válido; portanto, evalconverte a string em um objeto JavaScript (que funciona, desde que a string represente JavaScript válido, mesmo que não seja JSON válido). Em seguida, JSON.stringifyconverte de um objeto em uma sequência JSON (válida). A chamada evalé perigosa se a string não for de uma fonte confiável, pois poderia literalmente executar qualquer JavaScript que abra a possibilidade de ataques de script entre sites.
Matthew Crumley

2
eval ainda fará coisas ruins nesse caso se a string for construída, por exemplo, assim: var str = "(function () {console.log (\" bad \ ")})) ()";
Rondo

Usar eval () executará o código JS. Pode ser facilmente abusado.
FisNaN 02/02

@ allenhwkim: nunca confiamos em nenhuma fonte. Confiar em TI significa verificar, verificar e verificar novamente.
Laszlo Varga

110

Sua string não é JSON válida, portanto JSON.parse(ou do jQuery $.parseJSON) não funcionará.

Uma maneira seria usar evalpara "analisar" o JSON "inválido" e depois stringify"convertê-lo" para JSON válido.

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

Sugiro que, em vez de tentar "consertar" seu JSON inválido, você comece com JSON válido em primeiro lugar. Como está strsendo gerado, deve ser corrigido lá, antes de ser gerado, não depois.

EDIT : Você disse (nos comentários) esta string é armazenada em um atributo de dados:

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

Eu sugiro que você corrija aqui, para que possa ser apenas JSON.parsed. Primeiro, as chaves e os valores precisam ser citados entre aspas duplas. Deve ter a aparência (atributos de aspas simples em HTML são válidos):

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

Agora, você pode apenas usar JSON.parse(ou jQuery $.parseJSON).

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

49

jQuery.parseJSON

str = jQuery.parseJSON(str)

Editar. Isso é fornecido se você tiver uma sequência JSON válida


1
verdade eu vi a questão de como converter string JSON para objeto
Farmor

43

Use código simples no link abaixo:

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

e reverter

var str = JSON.stringify(arr);

Converter jsontext em um objeto String via nova String (jsontext) provavelmente é ainda melhor, para segurança do tipo.
Análise Difusa

@fuzzyanalysis: Não, invólucros primitivos nunca devem ser usados.
Ry-

1
JSON.parse () deve ser a resposta aceita aqui, como indicado por @LouiseMcMahon
pixel 67

24

Espero que essa pequena função converta uma string JSON inválida para uma 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…}

Estamos tentando desvalorizar b usando JSON.parse nosso código e isso parece uma boa solução. Ainda vamos ter que lidar com a substituição constante manualmente, mas pelo menos isso permite conter esses casos.
Ravemir

1
É quase perfeito. Não funciona quando : está em um dos valores.
Seler

9

Use com cuidado (por causa de eval()):

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

chamar como:

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

3
Para o eleitor anônimo. Eu desafio você a fornecer uma solução melhor. Tirando isso, uma razão para a votação seria boa.
precisa saber é o seguinte

1
@Rocket: Você está errado. a) eval()é a única maneira de fazê-lo. b) Eu avisei o OP sobre isso. c) Veja a resposta de Matthew Crumley e pense em uma explicação melhor. (Ah, e d) a declaração eval()é ruim é um absurdo nesta forma generalizada).
Tomalak

2
@Rocket: Ah, mal entendido ali. Desculpe, pensei que o voto negativo era seu. :)
Tomalak

1
@kuboslav: Funciona bem, você já testou? Ele está fazendo o eval("var x = " + str + ";")que é JS totalmente válido. Você não precisa fazer var x = ({a:12}).
Rocket Hazmat

2
@kuboslav Ele não funciona no IE7 porque o IE7 não possui suporte JSON nativo. Ele começará a funcionar assim que você usar json2.js. Não seja tão feliz em disparar.
precisa saber é o seguinte

4

Isenção de responsabilidade: não tente fazer isso em casa ou para qualquer coisa que exija que outros desenvolvedores o levem a sério:

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

Lá eu fiz.
Tente não fazê-lo, pois eval é ruim para você. Como dito acima, use o calço JSON de Crockford para navegadores mais antigos (IE7 e inferiores)

Esse método requer que sua sequência seja javascript válido , que será convertido em um objeto javascript que pode ser serializado em JSON.

editar: corrigido como sugerido pelo Rocket.


Deveria ser JSON.stringify(eval('('+str+')'));, não que eu desculpe eval, mas sua string não é JSON válida, portanto JSON.parsenão funciona.
Rocket Hazmat

4

Eu coloquei minha resposta para alguém que esteja interessado neste tópico antigo.

Eu criei o analisador de dados- * HTML5 para o plugin jQuery e demo que convertem uma string JSON malformada em um objeto JavaScript sem usar eval().

Ele pode passar os dados HTML5- * abaixo:

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

no objeto:

{
    hello: "world"
}


2

Há uma maneira muito mais simples de realizar essa façanha, basta seqüestrar o atributo onclick de um elemento fictício para forçar o retorno da sua string como um 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 ;)

Aqui está uma demonstração: http://codepen.io/csuwldcat/pen/dfzsu (abra seu console)


2

Você precisa usar "eval", JSON.stringify e JSON.parse para o resultado.

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

insira a descrição da imagem aqui


1

Você precisa escrever colchetes, porque sem eles evalconsiderará o código entre colchetes como um bloco de comandos.

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

1

Sua melhor e mais segura aposta seria JSON5 - JSON for Humans . É criado especificamente para esse 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>


1

Usar new Function () é melhor que eval, mas ainda deve ser usado apenas com 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 }

Fontes: MDN , 2ality


0

Para o seu exemplo simples acima, você pode fazer isso usando 2 substituições simples de regex:

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

Advertência grande : Essa abordagem ingênua pressupõe que o objeto não tenha seqüências contendo um caractere 'ou :. Por exemplo, não consigo pensar em uma boa maneira de converter a seguinte sequência de objetos em JSON sem usar eval:

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

0

Apenas pelas peculiaridades, você pode converter sua string via 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>


0

var str = "{olá: 'mundo', lugares: ['África', 'América', 'Ásia', 'Austrália']}" var fStr = str .replace (/ ([Az] *) (:) / g, '"$ 1":') .replace (/ '/ g, "\" ")

console.log (JSON.parse (fStr))insira a descrição da imagem aqui

Desculpe, eu estou no meu telefone, aqui está uma foto.


0

Uma solução com um regex e não usando eval:

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

Acredito que isso funcione para várias linhas e todas as ocorrências possíveis (sinalizador / g) de 'string' de aspas simples substituídas por "string" de aspas duplas.


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

-1

Talvez você precise tentar o seguinte:

str = jQuery.parseJSON(str)

Pergunta especificada "ou jQuery" e esta é a solução perfeita se você a tiver disponível.
Ecropolis
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.