Як перевірити, чи є рядок дійсним рядком JSON в JavaScript без використання Try / Catch


548

Щось на зразок:

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

//should be true
IsJsonString(jsonString);

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

Розчин не повинен містити спробу / лову. Деякі з нас включають "перерва на всі помилки", і їм не подобається, що налагоджувач порушується на цих недійсних рядках JSON


25
Чи є поважна причина не використовувати try?
Нік Т

7
@NickT Тому що якщо ви включите "на всіх помилках" у налагоджувачі, це станеться. Зараз у Chrome є можливість виправити помилки, що не виникають.
Чі Чан

6
Скористайтеся лише двома рядками, щоб перевірити це із спробою лову. var isValidJSON = вірно; спробуйте {JSON.parse (jsonString)} ловити {isValidJSON = false; }
efkan

18
Хоча це працює, це жахливо дивовижно і погана практика. Try / catch призначений для виняткової поведінки та керування помилками, а не загальним потоком програми.
Тасгалл

7
@Tasgall Як правило, так. Але що ви робите, якщо підхід «пробування / лову» є більш ефективним, ніж будь-який підхід на основі валідатора? Перейти з (іноді значно) повільнішим варіантом лише тому, що альтернатива "погана практика"? Немає нічого функціонально неправильного з методом try / catch, тому немає причин не використовувати його. Важливо, щоб нові програмісти розробляли хороші стандарти кодування, але не менш важливо не посилювати сліпе дотримання звичайних вказівок, особливо у випадках, коли вказівки ускладнюють справи, ніж вони повинні бути.
Авіон47

Відповіді:


172

Перший коментар. Питання стосувалося не використання try/catch.
Якщо ви не проти використовувати його, прочитайте відповідь нижче. Тут ми просто перевіряємо JSONрядок за допомогою regexp, і він буде працювати в більшості випадків, не у всіх випадках.

Огляньте лінію 450 на https://github.com/douglascrockford/JSON-js/blob/master/json2.js

Існує регулярне вираження, яке перевіряє чинність JSON, наприклад:

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 : Нова версія json2.js робить більш вдосконалений синтаксичний аналіз, ніж вище, але все ж заснований на заміні регулярного виразу (з коментаря @Mrchief )


59
Це лише перевірка того, чи безпечний код для використання eval. Наприклад, наступний рядок "2011-6-27" пройде цей тест.
SystemicPlural

4
@SystemicPlural, так, але питання стосувалося не використання try / catch
Mic

8
Ви не можете перевірити, чи є строка дійсною JSON з регулярним виразом в JavaScript, оскільки JS-регекси не підтримують необхідні розширення (рекурсивні регекси), які дозволяють вам це робити. Ваш вище код не вдається на "{".
Venge

2
@Mic json2.js більше не використовує просту перевірку (натомість використовує 4-ступінний аналіз для визначення дійсного JSON). Я б запропонував переглянути або видалити свою відповідь. Зауважте, що я не думаю, що немає нічого поганого в тому, щоб "не мати спробу / лову як єдиний механізм для перевірки JSON" як підходу.
Mrchief

8
Тільки тому, що це допомагає йому, не означає, що це допомагає і нам, у кого через роки виникає те саме питання.
Маккей

916

Використовуйте аналізатор JSON, наприклад JSON.parse:

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

7
Дякую, але я просто запустив це з командою, і вони хочуть чогось, що не використовує спробувати. Питання редагується разом із новою назвою. Вибач за те.
Чи Чан

4
@trejder: це так, тому що 1 не є рядком, спробуйте це з "1"
Purefan

31
@Gumbo Моєму коментарю 1,5 року! :] Я не пам’ятаю, що я робив два тижні тому, і ви просите мене згадати той проект? :] Ні, спосіб ...:]
trejder

9
Проблема з цією відповіддю полягає в тому, що якщо рядок перевіряється, і ви її розбираєте, ви її проаналізували двічі. Чи не могли ви замість цього повернути помилковий помилковий аналіз, але повернути об’єкт на успіх?
Carcigenicate

5
@Carcigenicate Ви можете це зробити. Однак також JSON.parse("false")оцінюється як хибне .
Gumbo

445

Я знаю, що я запізнився на 3 роки з цим питанням, але мені здалося, що я звучав.

Хоча рішення Gumbo чудово працює, воно не обробляє декілька випадків, коли не робиться виняток JSON.parse({something that isn't JSON})

Я також вважаю за краще одночасно повернути розібраний JSON, тому код виклику не потрібно дзвонити JSON.parse(jsonString)вдруге.

Це, здається, працює добре для моїх потреб:

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
З відповідей на сторінці це найбільш надійний і надійний.
Jonline

28
o && o !== nullзайве.
Олексій Матюшкін

4
Так є використання потрійних рівних з typeof, який завжди повертає рядок. :)
Хайн Харальдсон Берг

5
Незважаючи на старий пост, я подумав , що варто поставити скрипку вгору демонструючи свою відповідь @matth, будь ласка , зверніть увагу , що об'єкти не будуть діяти .. Ви повинні передати рядок JSON. Я можу стати в нагоді для кожного, хто починає я здогадуюсь.
MindVox

2
Функція повинна повертатися undefinedне falseтому, що falseє дійсним рядком json, і немає можливості розмежувати між ними tryParseJSON("false")іtryParseJSON("garbage")
резербайти

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

Використання: isJSON({}) буде false, isJSON('{}')буде true.

Для того, щоб перевірити , якщо що - то є Arrayабо Object( розібраний JSON):

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

Використання: isAO({}) буде true, isAO('{}')буде false.


4
Будьте уважні, оскільки nullпроходить цю перевірку.
Farzad YZ

2
return !!(JSON.parse(str) && str);повинен блокувати нульові значення. Я оновлю відповідь цим кодом.
Мачадо

1
Це найкраща відповідь, оскільки вона також дозволяє перевірити, чи був JSON об'єктивований , і, таким чином, не пройшов parse()тест, викликаючи WTF.
not2qubit

30

Ось мій робочий код:

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

1
IsJsonString (null); // повертає true. Це можна виправити, порівнюючиtypeof str === 'string'
грамча

22

Я використовував дуже простий метод, щоб перевірити рядок, наскільки це дійсний JSON чи ні.

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

Результат з допустимим рядком JSON:

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

Результат простим рядком;

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

Результат з об'єктом:

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

Результат з нульовим введенням:

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

Останній повертає помилково, оскільки тип нульових змінних є об'єктом.

Це працює щоразу. :)


1
JSON.parse (null), JSON.parse ("false") не видає помилок, напевно, є більше прикладів
klomoma

Так, ти маєш рацію, я забув перевірити, як вхідний рядок чи ні, якщо я це зробив, цей метод із nullвведенням він повертає помилково. Але "хибний" вхід - це дійсний рядок JSON. Це буде проаналізовано boolean (false). Тепер я модифікую код, щоб бути більш точним.
кукко

15

У прототипі JS у нас є метод isJSON . Ви можете спробувати це. Навіть json може допомогти.

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

9
Дякую, але я думаю, що використання бібліотеки прототипів для цього є трохи зайвою.
Чі Чан

4
Ви навели ЧЕТВЕРТИ приклади, але лише ТРИ результати. Для чого результат "{ foo: 42 }".isJSON()? Якщо false, як я припускаю, (результат повинен відповідати функціональному документу), то хорошим питанням є, чому він помилковий? { foo: 42 }здається, абсолютно справедливий JSON.
трейдер

4
@trejder На жаль, для специфікації JSON потрібні цитовані ключі.
mikermcneil

4
І "2002-12-15" .isJSON повертає істину, тоді як JSON.parse ("2002-12-15") видає помилку.
ychaouche

4
Я думаю, що кращою відповіддю тут було б витягнути цю функцію з бібліотеки прототипів і розмістити її тут. Тим більше, що api.prototypejs.org/language/string/prototype/isjson дорівнює 404.
jcollum

5

З String.isJSONвизначення рам прототипу тут

/**
   *  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);
  }

тому це версія, яку можна використовувати при передачі рядкового об'єкта

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
У когось є тестовий набір для порівняння всіх цих відповідей? Я хотів би дізнатися, чи правильно це.
Lonnie Best

1
@LonnieBest хороший момент. Мої 2 копійки. Я використовував роками у виробництві, і це завжди працювало чудово і з розумним часом виконання.
loretoparisi

4

Ця відповідь дозволяє зменшити витрати на операцію трикзача.

Я використовував JQuery для розбору рядків JSON, і я використовував операцію trycatch для обробки винятків, але викидання винятків для нерозбірних рядків уповільнило мій код, тому я використав простий Regex для перевірки рядка, чи це можливий рядок JSON чи ні, не пішовши перо перевіривши його синтаксис, тоді я використав звичайний спосіб, розбираючи рядок за допомогою JQuery:

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

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

}

Я загорнув попередній код у рекурсивну функцію для розбору вкладених відповідей JSON.


Що робить jQuery, що JSON.parse () не робить?
ADJenks

3

Можливо, це стане в нагоді:

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

вихід:

IE7: рядок , об'єкт, рядок, рядок

ХРОМ: об’єкт, об’єкт, рядок, рядок


2

Я думаю, я знаю, чому ти хочеш цього уникнути. Але, можливо, спробуйте і зловити! == спробувати і зловити. ; o) Це мені прийшло в голову:

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

Тому ви також можете забруднити кліп на об'єкт JSON, як-от:

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

Оскільки це можливо максимально капсульоване, воно може не помилитися.


2

Ось і версія друкарської версії:

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

Машинопис не JavaScript, але ваша відповідь, здається, є.
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

З вступного коментаря випливаю, що випадок використання визначає, чи є відповідь HTML чи JSON. У цьому випадку, коли ви робите отримати JSON, ви , ймовірно , повинен бути розбір його і обробки недійсних JSON в якій - то момент в вашому коді в будь-якому випадку. Окрім нічого, я думаю, що ви хотіли б, щоб вас повідомляв ваш веб-переглядач, якщо слід очікувати JSON, але недійсний JSON (як і користувачі через проксі-сервер якогось змістовного повідомлення про помилку)!

Виконання повного регулярного вираження для JSON є непотрібним (як це було б - на мій досвід - для більшості випадків використання). Можливо, вам буде краще використовувати щось на кшталт наведеного нижче:

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
  }
}

це повинно врятувати вас з необхідністю обробляти винятковий не-JSON код і одночасно піклуватися про duff json.


Це гібридне рішення здається, що це було б ефективним способом уникнути необхідності пробувати улов у більшості випадків, що не належать до JSON. Мені подобається цей аспект вашого підходу.
Lonnie Best

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

сподіваємось, що це працює і для вас


0
function get_json(txt)
{  var data

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

   return data;
}

Якщо є помилки, поверніть хибні.

Якщо помилок немає, поверніть дані json


4
У питанні: "Рішення не повинно містити спробу / лову".
ddmps

1
Чому? Це гарантований спосіб ... Нерозумно було б використовувати! Вибачте за те, що не знаю англійської. Я використовував Google Translate
Emrah Tuncel

Цікаво. Я хотів би побачити порівняння продуктивності JSON.parse з цим рішенням на основі eval. Але це виглядає страшно з точки зору безпеки / ін'єкцій.
Lonnie Best

0

Ви можете використовувати функцію javascript eval (), щоб перевірити, чи справді вона.

напр

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
}

Крім того, ви можете використовувати JSON.parseфункцію з json.org :

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

if (json) {
  //this is json
}

Сподіваюсь, це допомагає.

УВАГА : eval()це небезпечно , якщо хто - то приєднав шкідливий код JS, так як він буде виконувати. Переконайтеся, що струна JSON є надійною , тобто ви отримали її з надійного джерела.

Редагувати Для мого першого рішення рекомендується це зробити.

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

Щоб гарантувати json-ness. Якщо jsonStringне чистий JSON, eval викине виняток.


Перший приклад використання eval говорить, що "<div> foo </div>" є дійсним JSON. Це може працювати по-різному в різних браузерах, але виявляється, що у FireFox, eval () приймає XML.
Марк Льютон

Дякую, але я просто запустив це з командою, і вони хочуть чогось, що не використовує спробувати. Питання редагується разом із новою назвою. Вибач за те.
Чи Чан

@Mark Lutton, тип об'єкта не буде JSON, а документа XML Dom (я забув, що таке тип firefox).
Бухаке Сінді

1
eval також приймає дійсний JavaScript, наприклад, "попередження (5);" та рядки в одиничних лапках, які не є дійсними JSON.
Марк Луттон

12
Це чистий евал.
Кріс Бейкер

0

О, ви, безумовно, можете спробувати catch, щоб перевірити, чи дійсний JSON його чи ні

Випробувано на Firfox Quantom 60.0.1

використовувати функцію всередині функції, щоб протестувати JSON і використовувати цей вихід для перевірки рядка. чує приклад.

    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

Функція IsJsonString(str), яка використовується JSON.parse(str), не працює в моєму випадку.
Я намагався перевірити вихід json з GraphiQL, він завжди повертав помилковий. Пощастило, IsJON працює краще:

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

});

Вибірка зразка:

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

Для людей, яким подобається .Net умова функцій "спробувати", які повертають булеву функцію та обробляють параметр byref, що містить результат. Якщо вам не потрібен параметр out, ви можете опустити його і просто використовувати повернене значення.

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

-1

Дуже простий однолінійний код (але підхід Хакі)

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

ПРИМІТКА. Це працює лише в тому випадку, якщо ви очікуєте, що це такий рядок JSON, як id. Я використовую його для API і очікую результату або в JSON, або в якійсь помилці.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.