Как проверить, является ли строка допустимой строкой 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>")

Решение не должно содержать try / catch. Некоторые из нас включают «разбить все ошибки», и им не нравится, когда отладчик ломает эти недопустимые строки JSON.


25
Есть ли веская причина не использовать try?
Ник Т

7
@NickT Потому что, если вы включите «разбить все ошибки» в отладчике, он будет. В Chrome теперь есть возможность исправления ошибок.
Чи Чан

6
Используйте только 2 строки, чтобы проверить это с помощью команды try catch. var isValidJSON = true; try {JSON.parse (jsonString)} catch {isValidJSON = false; }
efkan

18
Хотя это работает, это ужасно грязная и плохая практика. Try / catch предназначен для исключительного поведения и обработки ошибок, а не общего потока программы.
Tasgall

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

Ответы:


172

Сначала комментарий. Вопрос был о неиспользовании try/catch.
Если вы не против его использовать, прочитайте ответ ниже. Здесь мы просто проверяем JSONстроку с помощью регулярного выражения, и она будет работать в большинстве случаев, а не во всех.

Посмотрите вокруг линии 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

}

РЕДАКТИРОВАТЬ : новая версия json2.js делает более сложный синтаксический анализ, чем выше, но все еще основанный на замене регулярного выражения (из комментария @Mrchief )


59
Это только проверка, безопасен ли код для использования в eval. Например, следующая строка «2011-6-27» пройдет этот тест.
SystemicPlural

4
@SystemicPlural, да, но вопрос был о том, чтобы не использовать try / catch
Mic

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

2
@Mic json2.js больше не использует эту простую проверку (вместо этого используется четырехэтапный анализ для определения действительного JSON). Предложил бы пересмотреть или удалить свой ответ. Обратите внимание, что я не думаю, что есть что-то неправильное в том, что «не использовать try / catch в качестве единственного механизма проверки JSON» в качестве подхода.
Mrchief

8
То, что это помогает ему, не означает, что это помогает остальным из нас, у которых спустя годы возник такой же вопрос.
МакКей,

917

Используйте синтаксический анализатор JSON, например JSON.parse:

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

7
Спасибо, но я только что проверил это с командой, и они хотят что-то, что не использует try / catch. Вопрос редактируется вместе с новым названием. Прости за это.
Чи Чан

4
@trejder: он делает это, потому что 1 не строка, попробуйте это с "1"
Purefan

31
@ Гамбо Моему комментарию 1,5 года! :] Я не помню, чем я занимался две недели назад, и вы просили меня вспомнить этот проект? :] Нет, кстати ...:]
Трейдер

9
Проблема с этим ответом состоит в том, что если строка проверяется, и вы ее анализируете, вы проанализировали ее дважды. Не могли бы вы вместо этого вернуть false при плохом разборе, но вернуть объект в случае успеха?
Carcigenicate

5
@Carcigenicate Вы могли бы сделать это. Тем не менее, JSON.parse("false")оценивается как ложное .
Гамбо

446

Я знаю, что я опоздал на этот вопрос на 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
Из ответов на странице это самый надежный и надежный.
Джонлайн

28
o && o !== nullэто лишнее.
Алексей Матюшкин

4
Так что используется тройное равенство с typeof, который всегда возвращает строку. :)
Хейн Харальдсон Берг

5
Несмотря на то, что это был старый пост, я подумал, что стоит поставить скрипку , демонстрирующую ваш ответ @matth, обратите внимание, что объекты не будут действительными. Вы должны передать строку JSON. Думаю, может пригодиться любому, кто только начинает.
MindVox

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

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 (нуль); // возвращает истину Это можно исправить, сравнивtypeof str === 'string'
Грамча

23

Я использовал очень простой метод, чтобы проверить строку, является ли она действительным 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;

Последний возвращает false, потому что типом нулевых переменных является объект.

Это работает каждый раз. :)


1
JSON.parse (null), JSON.parse ("false") не выдает ошибок, возможно, есть и другие примеры
klodoma

Да, вы правы, я забыл проверить, является ли ввод строкой или нет. Если я это сделаю, этот метод с nullвводом вернет false. Но «ложный» вход является допустимой строкой JSON. Это будет проанализировано boolean (false). Теперь я изменяю код, чтобы быть более точным.
kukko

15

В prototypeJS у нас есть метод 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 возвращает true, а 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
У кого-нибудь есть набор тестов для сравнения всех этих ответов? Я хотел бы увидеть, если это правильно.
Лонни Бест

1
@LonnieBest хороший момент. Мои 2 цента. Я годами использовал в производстве, и он всегда работал нормально и с разумным временем выполнения.
Лоретопариси

4

Этот ответ позволит снизить стоимость оператора trycatch.

Я использовал 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

Я думаю, я знаю, почему вы хотите избежать этого. Но, возможно, попробуй и поймай! == попробуй и поймай. о) Это пришло мне в голову:

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

Typescript не является JavaScript, но ваш ответ, кажется,.
Лонни Бест

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. Мне нравится этот аспект вашего подхода.
Лонни Бест

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

Если есть ошибки, верните false.

Если ошибок нет, верните данные json


4
В вопросе: «Решение не должно содержать try / catch».
ddmps

1
Почему? Это гарантированный способ ... Было бы глупо не использовать! Извините, что не знаю английский. Я использовал Google Translate
Эмра Тунсел

Интересно. Я хотел бы видеть сравнение производительности JSON.parse с этим решением на основе eval. Тем не менее, это выглядит страшно с точки зрения безопасности / инъекций.
Лонни Бест

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-несс. Если jsonStringне чистый JSON, eval выдаст исключение.


В первом примере с использованием eval говорится, что «<div> foo </ div>» является допустимым JSON. В разных браузерах он может работать по-разному, но в FireFox eval () принимает XML.
Марк Латтон

Спасибо, но я только что проверил это с командой, и они хотят что-то, что не использует try / catch. Вопрос редактируется вместе с новым названием. Прости за это.
Чи Чан

@Mark Lutton, тип объекта будет не JSON, а XML Dom Document (я забыл, какой именно тип Firefox).
Бухаке Синди

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

12
Это чистый Eval.
Крис Бейкер

0

О, вы определенно можете использовать try 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, он всегда возвращал false. К счастью, isJSON работает лучше:

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 о функциях try, которые возвращают логическое значение и обрабатывают параметр 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
});

-2

Очень простой однострочный код (но хакерский подход)

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.