2012-03-09 20 views
24

Qual è il metodo più semplice per analizzare JSON "rilassato" ma evitare il male eval?Analizzare "rilassato" JSON senza eval

Il seguente genera un errore:

JSON.parse("{muh: 2}"); 

dal corretto JSON dovrebbe avere le chiavi citato: {"muh": 2}


mio caso d'uso è una semplice interfaccia di test che uso per scrivere i comandi JSON al mio nodo server. Finora ho semplicemente usato eval perché è solo un'applicazione di prova. Tuttavia, l'utilizzo di JSHint nell'intero progetto continua a infastidirmi su questo eval. Quindi mi piacerebbe un'alternativa sicura che permetta comunque una sintassi rilassata per le chiavi.

PS: io non voglio scrivere un parser me solo per il gusto di applicazione di test :-)

+2

Se si tratta di un'applicazione di prova, e si ha il controllo assoluto sul vostro input JSON, non c'è problema nell'uso di 'eval'. – bfavaretto

+0

Un'altra opzione sta usando JSON più appropriato 'JSON.parse'. Oltre a questo, immagino sia eval o scrivere il tuo parser. – bfavaretto

+7

@bfavaretto Questo è pericoloso. Sappiamo tutti quante volte il codice "test" entra in produzione. Si potrebbe anche iniziare con una base sicura. – hspain

risposta

7

Se non è possibile citare le chiavi quando si scrive la stringa, è possibile inserire le virgolette prima di utilizzare JSON .parse-

var s= "{muh: 2,mah:3,moh:4}"; 
s= s.replace(/([a-z][^:]*)(?=\s*:)/g, '"$1"'); 

var o= JSON.parse(s); 
/* returned value:[object Object] */ 
JSON.stringify(o) 
/* returned value: (String){ 
    "muh":2, "mah":3, "moh":4 
} 
+1

> '{muh: "foo", mah: 3, moh: 4}'. Replace (/ ([az] [^:] *) (? = \ S *:)/g, '"$ 1"') ; '{"muh": "" foo ", mah": 3, "moh": 4}' Ci stavo pensando, ma vedere l'esempio non lo taglia. È un po 'più complicato. – axkibe

+0

prova ad inserire virgolette su un JSON non valido come questo: '" {muh: true, notMuch: 123, pika: {pika: \ "chu \"}} "' il risultato sarà '{" muh ":" true, notMuch ": 123," pika ": {" pika ":" chu "}}' –

+1

Hai dimenticato di includere il modificatore/i nel tuo RegExp, come questo: 's = s.replace (/ ([az] [^:] *) (? = \ s *:)/gi, '"$ 1"'); ' – alevkon

16

sapete già questo, dal momento che si referred me here = D, ma immagino che potrebbe essere buono per documentare qui:

che avevo avuto per lungo tempo lo stesso desiderio di essere in grado di scrivere JSON "rilassato" che era ancora valido JS, quindi presi la valutazione di Douglas Crockford -free json_parse.js ed esteso per supportare funzioni ES5:

https://github.com/aseemk/json5

Questo modulo è accessibile npm e può essere utilizzato come un rimpiazzo per il metodo nativo JSON.parse(). (Il suo stringify() emette regolarmente JSON.)

Spero che questo aiuti! =)

12

Si potrebbe sanificare l'JSON utilizzando un'espressione regolare sostituzione:

var badJson = "{muh: 2}"; 
var correctJson = badJson.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": '); 
JSON.parse(correctJson); 
+2

Questa espressione regolare funziona, quella di @kennebec non funziona per JSON'value' che contiene un valore booleano –

+2

Se si aggiunge '\ s *' prima di ':/g', allora sarà anche possibile riparare stringhe JSON che hanno spazi prima dei due punti, come '{muh: 2}' – Malvineous

+1

Appena realizzato questa regex non riesce per i valori che contengono due punti, ad esempio '{muh:" 2:30 pm "}' – Malvineous

6

Questo è quello che ho finito per dover fare. Ho esteso @ risposta di ArnaudWeil e aggiunto il supporto per avere : appaiono nei valori:

var badJSON = '{one : "1:1", two : { three: \'3:3\' }}'; 
 

 
var fixedJSON = badJSON 
 

 
\t // Replace ":" with "@[email protected]" if it's between double-quotes 
 
\t .replace(/:\s*"([^"]*)"/g, function(match, p1) { 
 
\t \t return ': "' + p1.replace(/:/g, '@[email protected]') + '"'; 
 
\t }) 
 

 
\t // Replace ":" with "@[email protected]" if it's between single-quotes 
 
\t .replace(/:\s*'([^']*)'/g, function(match, p1) { 
 
\t \t return ': "' + p1.replace(/:/g, '@[email protected]') + '"'; 
 
\t }) 
 

 
\t // Add double-quotes around any tokens before the remaining ":" 
 
\t .replace(/(['"])?([a-z0-9A-Z_]+)(['"])?\s*:/g, '"$2": ') 
 

 
\t // Turn "@[email protected]" back into ":" 
 
\t .replace(/@[email protected]/g, ':') 
 
; 
 

 
console.log('Before: ' + badJSON); 
 
console.log('After: ' + fixedJSON); 
 
console.log(JSON.parse(fixedJSON));

produce questo output:

Before: {one : "1:1", two : { three: '3:3' }} 
After: {"one": "1:1", "two": { "three": "3:3" }} 
{ 
    "one": "1:1", 
    "two": { 
    "three": "3:3" 
    } 
} 
+0

In futuro è virtualmente garantito il superamento di alcuni casi limite. –

+1

@torazaburo: Certo, ma forse quando ciò accade qualcuno può costruirci sopra per risolvere il problema, proprio come ho costruito su una soluzione precedente per risolvere il problema che ho riscontrato. – Malvineous

+0

Uno strano approccio alla codifica: scrivere codice che probabilmente si romperà, programmando di risolverlo in seguito. –

0

JSON5 sembra piuttosto ben supportato, ma questo Anche la libreria relaxed-json sembra una buona opzione.

0

È anche possibile utilizzare NDS's really-relaxed-json (https://www.npmjs.com/package/really-relaxed-json) che fa un passo avanti e non consente virgole, virgolette, commenti, stringhe multilinea, ecc.

Ecco le specifiche http://www.relaxedjson.org

E alcuni parser on-line:
http://www.relaxedjson.org/docs/converter.html

precaricati con il 'cattivo JSON' {one : "1:1", two : { three: '3:3' }}

Bad JSON

precaricato con ancora 'JSON peggio' (nessuna virgola) {one : '1:1' two : { three: '3:3' }} Worse JSON

Precaricato con 'terribile JSON' (non virgole, senza virgolette, e due punti sfuggiti) {one : 1\:1 two : {three : 3\:3}} Terrible JSON