Come verificare se una stringa è una stringa JSON valida in JavaScript senza utilizzare Try / Catch


548

Qualcosa di simile a:

var jsonString = '{ "Id": 1, "Name": "Coke" }';

//should be true
IsJsonString(jsonString);

//should be false
IsJsonString("foo");
IsJsonString("<div>foo</div>")

La soluzione non deve contenere try / catch. Alcuni di noi attivano "rompi tutti gli errori" e non amano che il debugger si rompa su quelle stringhe JSON non valide.


25
C'è un motivo valido per non usare try?
Nick T

7
@NickT Perché se si attiva "rompi tutti gli errori" nel debugger, lo farà. Chrome ora ha la possibilità di rompere su errori non rilevati.
Chi Chan,

6
Usa solo 2 righe per controllarlo con prova a catturare. var isValidJSON = true; provare {JSON.parse (jsonString)} catch {isValidJSON = false; }
efkan,

18
Mentre funziona, è terribilmente ingannevole e cattiva pratica. Try / catch è pensato per comportamenti eccezionali e gestione degli errori, non per un flusso di programma generale.
Tasgall,

7
@Tasgall Come regola generale, sì. Ma cosa fai se l'approccio try / catch è più performante di qualsiasi approccio basato su validatore? Vai con l'opzione (a volte significativamente più lenta) solo perché l'alternativa è "cattiva pratica"? Non c'è nulla di funzionalmente sbagliato nel metodo try / catch, quindi non c'è motivo di non usarlo. È importante che i nuovi programmatori sviluppino buoni standard di codifica, ma è altrettanto importante non rafforzare la cieca aderenza alle linee guida convenzionali, specialmente nei casi in cui le linee guida rendono le cose più difficili di quanto debbano essere.
Abion47,

Risposte:


172

Prima un commento. La domanda riguardava il non utilizzo try/catch.
Se non ti dispiace usarlo, leggi la risposta qui sotto. Qui controlliamo solo una JSONstringa usando un regexp, e funzionerà nella maggior parte dei casi, non in tutti i casi.

Dai un'occhiata alla linea 450 in https://github.com/douglascrockford/JSON-js/blob/master/json2.js

Esiste una regexp che verifica la presenza di un JSON valido, qualcosa del tipo:

if (/^[\],:{}\s]*$/.test(text.replace(/\\["\\\/bfnrtu]/g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

  //the json is ok

}else{

  //the json is not ok

}

EDIT : la nuova versione di json2.js effettua un parsing più avanzato di quanto sopra, ma ancora basato su un regexp sostitutivo (dal commento di @Mrchief )


59
Questo sta solo verificando se il codice è sicuro da usare per eval. Ad esempio, la seguente stringa "2011-6-27" supererebbe tale test.
SystemicPlural,

4
@SystemicPlural, sì, ma la domanda era non usare try / catch
Mic

8
Non è possibile verificare se una stringa è JSON valida con una regex in JavaScript, poiché le regex JS non supportano le estensioni necessarie (regex ricorsive) che consentono di farlo. Il codice sopra riportato non riesce su "{".
Venge

2
@Mic json2.js non utilizza più quel semplice controllo (utilizza invece un'analisi in 4 fasi per determinare JSON valido). Suggerirei di rivedere o rimuovere la tua risposta. Si noti che non penso che ci sia qualcosa di sbagliato nel "non avere un tentativo / cattura come unico meccanismo per verificare la presenza di JSON" come approccio.
Mrchief,

8
Solo perché lo aiuta, non significa che aiuti il ​​resto di noi, che, anni dopo, ha la stessa domanda.
McKay,

917

Utilizzare un parser JSON come JSON.parse:

function IsJsonString(str) {
    try {
        JSON.parse(str);
    } catch (e) {
        return false;
    }
    return true;
}

7
Grazie, ma l'ho appena gestito con il team e vogliono qualcosa che non usi try / catch. La domanda viene modificata insieme a un nuovo titolo. Mi dispiace per quello.
Chi Chan,

4
@trejder: lo fa perché 1 non è una stringa, provalo con "1"
Purefan

31
@Gumbo Il mio commento ha 1,5 anni! :] Non ricordo cosa stavo facendo due settimane fa e mi hai chiesto di ricordare quel progetto? :] No, way ...:]
trejder

9
Il problema con questa risposta è che se la stringa viene estratta e la analizzi, la avrai analizzata due volte. Non potresti invece restituire false in caso di analisi errata, ma restituire l'oggetto in caso di successo?
Carcigenicato il

5
@Carcigenicato Potresti farlo. Tuttavia, JSON.parse("false")valuta anche falso .
Gumbo

446

So di essere in ritardo di 3 anni a questa domanda, ma mi andava di rispondere.

Mentre la soluzione di Gumbo funziona alla grande, non gestisce alcuni casi in cui non viene sollevata alcuna eccezione JSON.parse({something that isn't JSON})

Preferisco anche restituire il JSON analizzato allo stesso tempo, quindi il codice chiamante non deve chiamare JSON.parse(jsonString) una seconda volta.

Questo sembra funzionare bene per le mie esigenze:

function tryParseJSON (jsonString){
    try {
        var o = JSON.parse(jsonString);

        // Handle non-exception-throwing cases:
        // Neither JSON.parse(false) or JSON.parse(1234) throw errors, hence the type-checking,
        // but... JSON.parse(null) returns null, and typeof null === "object", 
        // so we must check for that, too. Thankfully, null is falsey, so this suffices:
        if (o && typeof o === "object") {
            return o;
        }
    }
    catch (e) { }

    return false;
};

9
Delle risposte sulla pagina, questa è la più solida e affidabile.
Jonline,

28
o && o !== nullè superfluo.
Aleksei Matiushkin,

4
Quindi sta usando triple-uguale a typeof, che restituisce sempre una stringa. :)
Hein Haraldson Berg,

5
Nonostante sia un vecchio post, ho pensato che valesse la pena mettere su un violino per dimostrare la tua risposta @matth, tieni presente che gli oggetti non saranno validi .. devi passare una stringa JSON. Potrebbe tornare utile per chiunque abbia iniziato immagino.
MindVox,

2
La funzione dovrebbe tornare undefined, non falseperché falseè una stringa json valida e non c'è modo di distinguere tra tryParseJSON("false")etryParseJSON("garbage")
sparebytes

54
// vanillaJS
function isJSON(str) {
    try {
        return (JSON.parse(str) && !!str);
    } catch (e) {
        return false;
    }
}

Uso: isJSON({}) sarà false, isJSON('{}')saràtrue .

Per verificare se qualcosa è un Arrayo Object( JSON analizzato ):

// vanillaJS
function isAO(val) {
    return val instanceof Array || val instanceof Object ? true : false;
}

// ES2015
var isAO = (val) => val instanceof Array || val instanceof Object ? true : false;

Uso: isAO({}) sarà true, isAO('{}')saràfalse .


4
Fai attenzione poiché nullpassa questa convalida.
Farzad YZ,

2
return !!(JSON.parse(str) && str);dovrebbe bloccare valori nulli. Aggiornerò la risposta con questo codice.
Machado,

1
Questa è la risposta migliore, poiché consente anche di verificare se il JSON è stato oggettivato , e quindi non ha superato il parse()test, causando WTF.
not2qubit

30

Ecco il mio codice di lavoro:

function IsJsonString(str) {
  try {
    var json = JSON.parse(str);
    return (typeof json === 'object');
  } catch (e) {
    return false;
  }
}

1
IsJsonString (null); // restituisce vero. Può essere risolto confrontandotypeof str === 'string'
gramcha il

23

Ho usato un metodo davvero semplice per controllare una stringa come sia o meno un JSON valido.

function testJSON(text){
    if (typeof text!=="string"){
        return false;
    }
    try{
        JSON.parse(text);
        return true;
    }
    catch (error){
        return false;
    }
}

Risultato con una stringa JSON valida:

var input='["foo","bar",{"foo":"bar"}]';
testJSON(input); // returns true;

Risultato con una stringa semplice;

var input='This is not a JSON string.';
testJSON(input); // returns false;

Risultato con un oggetto:

var input={};
testJSON(input); // returns false;

Risultato con input null:

var input=null;
testJSON(input); // returns false;

L'ultimo restituisce false perché il tipo di variabili null è object.

Funziona sempre. :)


1
JSON.parse (null), JSON.parse ("false") non genera errori, probabilmente ci sono altri esempi
klodoma

Sì, hai ragione, ho dimenticato di controllare come l'input è una stringa o no, se lo faccio, questo metodo con nullinput restituisce false. Ma l'input "false" è una stringa JSON valida. Questo verrà analizzato boolean (false). Ora modifico il codice per essere più preciso.
Kukko,

15

In prototypeJS, abbiamo il metodo isJSON . Puoi provarlo. Anche JSON potrebbe aiutare.

"something".isJSON();
// -> false
"\"something\"".isJSON();
// -> true
"{ foo: 42 }".isJSON();
// -> false
"{ \"foo\": 42 }".isJSON();

9
Grazie, ma penso che usare la libreria dei prototipi per farlo sia un po 'eccessivo.
Chi Chan,

4
Hai fornito QUATTRO esempi ma solo TRE risultati. A cosa serve il risultato "{ foo: 42 }".isJSON()? Se false, come presumo (il risultato dovrebbe seguire la funzione documenta), allora la buona domanda è: perché è falsa? { foo: 42 }sembra essere JSON perfettamente valido.
Trejder,

4
@trejder Sfortunatamente, le specifiche JSON richiedono chiavi tra virgolette.
mikermcneil,

4
E "2002-12-15" .isJSON restituisce true, mentre JSON.parse ("2002-12-15") genera un errore.
ychaouche,

4
Penso che la risposta migliore qui sarebbe estrarre quella funzione dalla libreria dei prototipi e inserirla qui. Soprattutto perché api.prototypejs.org/language/string/prototype/isjson è 404.
jcollum,

5

Dalla String.isJSONdefinizione del framework prototipo qui

/**
   *  String#isJSON() -> Boolean
   *
   *  Check if the string is valid JSON by the use of regular expressions.
   *  This security method is called internally.
   *
   *  ##### Examples
   *
   *      "something".isJSON();
   *      // -> false
   *      "\"something\"".isJSON();
   *      // -> true
   *      "{ foo: 42 }".isJSON();
   *      // -> false
   *      "{ \"foo\": 42 }".isJSON();
   *      // -> true
  **/
  function isJSON() {
    var str = this;
    if (str.blank()) return false;
    str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
    str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
    str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
    return (/^[\],:{}\s]*$/).test(str);
  }

quindi questa è la versione che può essere utilizzata passando un oggetto stringa

function isJSON(str) {
    if ( /^\s*$/.test(str) ) return false;
    str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
    str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
    str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
    return (/^[\],:{}\s]*$/).test(str);
  }

function isJSON(str) {
    if ( /^\s*$/.test(str) ) return false;
    str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
    str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
    str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
    return (/^[\],:{}\s]*$/).test(str);
  }

console.log ("this is a json",  isJSON( "{ \"key\" : 1, \"key2@e\" : \"val\"}" ) )

console.log("this is not a json", isJSON( "{ \"key\" : 1, \"key2@e\" : pippo }" ) )


1
Qualcuno ha una suite di test per confrontare tutte queste risposte? Mi piacerebbe vedere se questo è corretto.
Lonnie Best

1
@LonnieBest buon punto. I miei 2 centesimi. Ho usato per anni in produzione e ha sempre funzionato bene e con un tempo di esecuzione ragionevole.
Loretoparisi,

4

Questa risposta per ridurre il costo dell'istruzione trycatch.

Ho usato JQuery per analizzare le stringhe JSON e ho usato l'istruzione trycatch per gestire le eccezioni, ma lanciare eccezioni per stringhe non analizzabili ha rallentato il mio codice, quindi ho usato Regex semplice per controllare la stringa se è una possibile stringa JSON o no senza andare in piuma controllando la sua sintassi, quindi ho usato il modo normale analizzando la stringa usando JQuery:

if (typeof jsonData == 'string') {
    if (! /^[\[|\{](\s|.*|\w)*[\]|\}]$/.test(jsonData)) {
        return jsonData;
    }
}

try {
    jsonData = $.parseJSON(jsonData);
} catch (e) {

}

Ho racchiuso il codice precedente in una funzione ricorsiva per analizzare le risposte JSON nidificate.


Cosa fa jQuery che JSON.parse () non fa?
ADJenks,

3

Forse sarà utile:

    function parseJson(code)
{
    try {
        return JSON.parse(code);
    } catch (e) {
        return code;
    }
}
function parseJsonJQ(code)
{
    try {
        return $.parseJSON(code);
    } catch (e) {
        return code;
    }
}

var str =  "{\"a\":1,\"b\":2,\"c\":3,\"d\":4,\"e\":5}";
alert(typeof parseJson(str));
alert(typeof parseJsonJQ(str));
var str_b  = "c";
alert(typeof parseJson(str_b));
alert(typeof parseJsonJQ(str_b));

produzione:

IE7: stringa , oggetto, stringa, stringa

CHROME: oggetto, oggetto, stringa, stringa


2

Penso di sapere perché vuoi evitarlo. Ma forse prova a catturare! == prova a catturare. ; o) Mi è venuto in mente:

var json_verify = function(s){ try { JSON.parse(s); return true; } catch (e) { return false; }};

Quindi puoi anche sporcare la clip sull'oggetto JSON, come:

JSON.verify = function(s){ try { JSON.parse(s); return true; } catch (e) { return false; }};

Essendo quanto più incapsulato possibile, potrebbe non rompersi in caso di errore.


2

Ecco anche la versione dattiloscritta:

JSONTryParse(input) {
    try {
        //check if the string exists
        if (input) {
            var o = JSON.parse(input);

            //validate the result too
            if (o && o.constructor === Object) {
                return o;
            }
        }
    }
    catch (e) {
    }

    return false;
};

Typescript non è javascript, ma la tua risposta sembra essere.
Lonnie Best

1

var jsonstring='[{"ConnectionString":"aaaaaa","Server":"ssssss"}]';

if(((x)=>{try{JSON.parse(x);return true;}catch(e){return false}})(jsonstring)){

document.write("valide json")

}else{
document.write("invalide json")
}


1

Dal commento di apertura desumo che il caso d'uso stia delineando se una risposta è HTML o JSON. Nel qual caso, quando lo fai ricevere JSON, probabilmente dovrebbe essere l'analisi e la manipolazione delle JSON valido ad un certo punto nel codice in ogni caso. A parte tutto, immagino che ti piacerebbe essere informato dal tuo browser qualora JSON fosse previsto ma JSON non valido ricevuto (come faranno gli utenti per delega di alcuni messaggi di errore significativi)!

Fare una regex completa per JSON non è quindi necessario (come sarebbe - secondo la mia esperienza - per la maggior parte dei casi d'uso). Probabilmente staresti meglio usando qualcosa di simile al seguente:

function (someString) {
  // test string is opened with curly brace or machine bracket
  if (someString.trim().search(/^(\[|\{){1}/) > -1) {
    try { // it is, so now let's see if its valid JSON
      var myJson = JSON.parse(someString);
      // yep, we're working with valid JSON
    } catch (e) {
      // nope, we got what we thought was JSON, it isn't; let's handle it.
    }
  } else {
    // nope, we're working with non-json, no need to parse it fully
  }
}

ciò dovrebbe evitare di dover gestire eccezionalmente un codice non JSON valido e prendersi cura di duff json allo stesso tempo.


Questa soluzione ibrida sembra essere un modo efficace per evitare di dover fare un tentativo nella maggior parte dei casi non JSON. Mi piace quell'aspetto del tuo approccio.
Lonnie Best

1
if(resp) {
    try {
        resp = $.parseJSON(resp);
        console.log(resp);
    } catch(e) {
        alert(e);
    }
}

spero che questo funzioni anche per te


0
function get_json(txt)
{  var data

   try     {  data = eval('('+txt+')'); }
   catch(e){  data = false;             }

   return data;
}

In caso di errori, restituire false.

Se non ci sono errori, restituire i dati JSON


4
Nella domanda: "La soluzione non deve contenere try / catch".
ddmps,

1
Perché? Questo è un modo garantito ... Sarebbe sciocco da non usare! Mi dispiace per non conoscere l'inglese. Ho usato Google Translate
Emrah Tuncel il

Interessante. Mi piacerebbe vedere un confronto delle prestazioni di JSON.parse rispetto a questa soluzione basata su Eval. Eppure questo sembra spaventoso dal punto di vista della sicurezza / iniezione.
Lonnie Best

0

È possibile utilizzare la funzione javascript eval () per verificare se è valida.

per esempio

var jsonString = '{ "Id": 1, "Name": "Coke" }';
var json;

try {
  json = eval(jsonString);
} catch (exception) {
  //It's advisable to always catch an exception since eval() is a javascript executor...
  json = null;
}

if (json) {
  //this is json
}

In alternativa, puoi usare la JSON.parsefunzione di json.org :

try {
  json = JSON.parse(jsonString);
} catch (exception) {
  json = null;
}

if (json) {
  //this is json
}

Spero che sia di aiuto.

ATTENZIONE : eval()è pericoloso se qualcuno aggiunge codice JS dannoso, poiché lo eseguirà. Assicurarsi che la stringa JSON sia affidabile , ovvero che tu l'abbia ottenuta da una fonte attendibile.

Modifica Per la mia prima soluzione, si consiglia di farlo.

 try {
      json = eval("{" + jsonString + "}");
    } catch (exception) {
      //It's advisable to always catch an exception since eval() is a javascript executor...
      json = null;
    }

Per garantire json-ness. Se il jsonStringJSON non è puro, eval genererà un'eccezione.


Il primo esempio che utilizza eval dice che "<div> foo </div>" è JSON valido. Potrebbe funzionare in modo diverso nei diversi browser, ma sembra che in FireFox, eval () accetti XML.
Mark Lutton,

Grazie, ma l'ho appena gestito con il team e vogliono qualcosa che non usi try / catch. La domanda viene modificata insieme a un nuovo titolo. Mi dispiace per quello.
Chi Chan,

@Mark Lutton, il tipo di oggetto non sarà di JSON ma di XML Dom Document (ho dimenticato quale sia il tipo esatto in Firefox).
Buhake Sindi,

1
eval accetta anche JavaScript valido, come "alert (5);" e stringhe tra virgolette singole, che non sono JSON valide.
Mark Lutton,

12
Questo è puro eval.
Chris Baker,

0

Oh, puoi sicuramente usare try catch per verificare se è un JSON valido o meno

Testato su Firfox Quantom 60.0.1

utilizzare la funzione all'interno di una funzione per ottenere il test JSON e utilizzare tale output per convalidare la stringa. sente un esempio.

    function myfunction(text){

       //function for validating json string
        function testJSON(text){
            try{
                if (typeof text!=="string"){
                    return false;
                }else{
                    JSON.parse(text);
                    return true;                            
                }
            }
            catch (error){
                return false;
            }
        }

  //content of your real function   
        if(testJSON(text)){
            console.log("json");
        }else{
            console.log("not json");
        }
    }

//use it as a normal function
        myfunction('{"name":"kasun","age":10}')

0

La funzione IsJsonString(str)che sta usando JSON.parse(str)non funziona nel mio caso.
Ho provato a convalidare l'output json da GraphiQL che restituisce sempre false. Fortunatamente, isJSON funziona meglio:

var test = false;

$('body').on('DOMSubtreeModified', '.resultWrap', function() {

    if (!test) {   
        var resultWrap = "{" + $('#graphiql .resultWrap').text().split("{").pop();
        if isJSON(resultWrap) {test = !test;}
        console.log(resultWrap); 
        console.log(resultWrap.isJSON());
    }

});

Uscita campione:

THREE.WebGLRenderer 79
draw.js:170 {xxxxxxxxxx
draw.js:170 false
draw.js:170 {xxxxxxxxxx 
draw.js:170 false
draw.js:170 {xxxxxxxxxx 
draw.js:170 false
draw.js:170 {xxxxxxxxxx 
draw.js:170 false
draw.js:170 {​
draw.js:170 false
draw.js:170 {  "PI": 3.141592653589793,​
draw.js:170 false
draw.js:170 {  "PI": 3.141592653589793,  "time": 1570751209006,​
draw.js:170 false
draw.js:170 {  "PI": 3.141592653589793,  "time": 1570751209006,  "tick": 156,​
draw.js:170 false
draw.js:170 {  "PI": 3.141592653589793,  "time": 1570751209006,  "tick": 156,  "tickr": 1.56,​
draw.js:170 false
draw.js:170 {  "PI": 3.141592653589793,  "time": 1570751209006,  "tick": 156,  "tickr": 1.56,  "fps": 41.666666666666664,​
draw.js:170 false
draw.js:170 {  "PI": 3.141592653589793,  "time": 1570751209006,  "tick": 156,  "tickr": 1.56,  "fps": 41.666666666666664,  "width": 396.984,​
draw.js:170 false
draw.js:170 {  "PI": 3.141592653589793,  "time": 1570751209006,  "tick": 156,  "tickr": 1.56,  "fps": 41.666666666666664,  "width": 396.984,  "height": 327
draw.js:170 false
draw.js:170 {  "PI": 3.141592653589793,  "time": 1570751209006,  "tick": 156,  "tickr": 1.56,  "fps": 41.666666666666664,  "width": 396.984,  "height": 327}​
draw.js:170 false
draw.js:170 {  "PI": 3.141592653589793,  "time": 1570751209006,  "tick": 156,  "tickr": 1.56,  "fps": 41.666666666666664,  "width": 396.984,  "height": 327}
draw.js:170 true

0

Per le persone a cui piace la convenzione .Net delle funzioni "provare" che restituiscono un valore booleano e gestiscono un parametro byref contenente il risultato. Se non è necessario il parametro out, è possibile ometterlo e utilizzare semplicemente il valore restituito.

StringTests.js

  var obj1 = {};
  var bool1 = '{"h":"happy"}'.tryParse(obj1); // false
  var obj2 = {};
  var bool2 = '2114509 GOODLUCKBUDDY 315852'.tryParse(obj2);  // false

  var obj3 = {};
  if('{"house_number":"1","road":"Mauchly","city":"Irvine","county":"Orange County","state":"California","postcode":"92618","country":"United States of America","country_code":"us"}'.tryParse(obj3))
    console.log(obj3);

StringUtils.js

String.prototype.tryParse = function(jsonObject) {
  jsonObject = jsonObject || {};
  try {
    if(!/^[\[{]/.test(this) || !/[}\]]$/.test(this)) // begin / end with [] or {}
      return false; // avoid error handling for strings that obviously aren't json
    var json = JSON.parse(this);
    if(typeof json === 'object'){
      jsonObject.merge(json);
      return true;
    }
  } catch (e) {
    return false;
  }
}

ObjectUtils.js

Object.defineProperty(Object.prototype, 'merge', {
  value: function(mergeObj){
    for (var propertyName in mergeObj) {
      if (mergeObj.hasOwnProperty(propertyName)) {
        this[propertyName] = mergeObj[propertyName];
      }      
    }
    return this;
  },
  enumerable: false, // this is actually the default
});

-2

Codice one-liner molto semplice (ma approccio Hacky)

if (expected_json.id === undefined){
   // not a json
}
else{
   // json
}

NOTA: Funziona solo se ti aspetti che qualcosa sia una stringa JSON come id. Lo sto usando per un'API e mi aspetto il risultato in JSON o in qualche stringa di errore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.