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.

snorpey
fonte
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).

Matthew Crumley
fonte
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);
Foguete Hazmat
fonte
49

jQuery.parseJSON

str = jQuery.parseJSON(str)

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

Farmor
fonte
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);
Ronald
fonte
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…}
allenhwkim
fonte
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) );
Tomalak
fonte
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.

gonchuki
fonte
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"
}
tokkonopapa
fonte
2

Douglas Crockford tem um conversor, mas não tenho certeza se isso ajudará com JSON ruim a bom JSON.

https://github.com/douglascrockford/JSON-js

Seth
fonte
Isso realmente não ajuda, pois a sequência não é JSON válida.
Rocket Hazmat
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)

csuwldcat
fonte
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

Negi Rox
fonte
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'] })");
Kuboslav
fonte
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>

dereli
fonte
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

SamGoody
fonte
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\"] }"
Topher Hunt
fonte
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>

Moritz Roessler
fonte
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.

Francis Leigh
fonte
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.

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

Talvez você precise tentar o seguinte:

str = jQuery.parseJSON(str)
howdyhyber
fonte
Pergunta especificada "ou jQuery" e esta é a solução perfeita se você a tiver disponível.
Ecropolis