如何在不使用Try / Catch的情况下检查字符串在JavaScript中是否为有效的JSON字符串


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
Nick T

7
@NickT因为如果您在调试器中打开“打破所有错误”,它将打开。Chrome现在可以选择解决未捕获的错误。
Chi Chan

6
仅使用2行即可通过try catch检查它。var isValidJSON = true; 尝试{JSON.parse(jsonString)} catch {isValidJSON = false; }
efkan '16

18
尽管这行得通,但是这却是极度混乱和糟糕的做法。尝试/捕获旨在实现特殊的行为和错误处理,而不是常规程序流程。
塔斯加尔

7
@Tasgall作为一般规则,是的。但是,如果try / catch方法比任何基于验证器的方法更高效,该怎么办?选择(有时明显)较慢的选项,只是因为另一种选择是“不良做法”?try / catch方法在功能上没有任何问题,因此没有理由不使用它。让新程序员开发良好的编码标准很重要,但同样重要的是,不要盲目遵守常规准则,尤其是在准则使事情变得比原本需要困难的情况下。
Abion47年

Answers:


172

首先发表评论。问题是关于不使用try/catch
如果您不介意使用它,请阅读以下答案。在这里,我们仅JSON使用正则表达式检查字符串,它在大多数情况下(并非在所有情况下)都适用。

看看https://github.com/douglascrockford/JSON-js/blob/master/json2.js中的 450行

有一个正则表达式,用于检查有效的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
您无法使用JavaScript中的正则表达式来测试字符串是否为有效的JSON,因为JS正则表达式不支持让您这样做的必要扩展(递归正则表达式)。您的上述代码在“ {”上失败。
Venge 2014年

2
@Mic json2.js不再使用该简单检查(而是使用4阶段解析来确定有效JSON)。建议修改或删除您的答案。请注意,我认为“不使用try / catch作为检查JSON的唯一机制”没有任何错误。
Mrchief

8
仅仅因为它对他有帮助,并不意味着它对我们其余的人有帮助,而这些人在几年后也有同样的问题。
麦凯

916

使用JSON解析器,例如JSON.parse

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

7
谢谢,但是我只是和团队一起使用,他们想要一些不使用try / catch的东西。该问题与新标题一起被编辑。对于那个很抱歉。
Chi Chan 2010年

4
@trejder:这样做是因为1不是字符串,请尝试使用“ 1”
Purefan 2014年

31
@Gumbo我的评论已经1.5岁了!:]我不记得了,我两周前在做什么,您问我是否记得那个项目?:]不,方法...:]
trejder 2014年

9
这个答案的问题是,如果该字符串确实签出,并且您对其进行了解析,则将其解析两次。您能否在错误的分析中返回false,但在成功时返回该对象呢?
Carcigenicate's

5
@Carcigenicate您可以这样做。但是,也将其JSON.parse("false")评估为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
在页面上的答案中,这是最可靠和可靠的。
2014年

28
o && o !== null是多余的。
Aleksei Matiushkin 2014年

4
在typeof中使用三重等于总是返回一个字符串。:)
Hein Haraldson Berg 2014年

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({})falseisJSON('{}')true

要检查某物是否为ArrayObject已解析的 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({})trueisAO('{}')false


4
请小心,因为null通过了此验证。
法尔扎德YZ

2
return !!(JSON.parse(str) && str);应该阻止空值。我将用此代码更新答案。
马查多

1
这是最好的答案,因为它还允许您检查JSON是否已被对象,从而不通过parse()测试,从而导致WTF。
not2qubit

29

这是我的工作代码:

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

1
IsJsonString(null); //返回true。可以通过比较来解决typeof str === 'string'
gramcha '19

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;

最后一个返回false,因为null变量的类型是object。

每次都有效。:)


1
JSON.parse(null),JSON.parse(“ false”)不会引发错误,可能还有更多示例
klodoma

是的,您是对的,我忘了检查输入是否为字符串,如果这样做,此方法将 null输入的将返回false。但是“ false”输入是有效的JSON字符串。这将解析为boolean (false)。现在,我将代码修改为更准确。
kukko

15

在prototypeJS中,我们有方法isJSON。你可以试试看。甚至json也可能有帮助。

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

9
谢谢,但是我认为使用原型库执行此操作有些过分了。
Chi Chan 2010年

4
您给出了四个示例,但只有三个结果。结果是"{ foo: 42 }".isJSON()什么?如果false我假设(结果应该跟随函数文件),那么好的问题是,为什么它是错误的?{ foo: 42 }似乎是完全有效的JSON。
trejder 2012年

4
@trejder不幸的是,JSON规范需要带引号的键。
mikermcneil 2012年

4
并且“ 2002-12-15” .isJSON返回true,而JSON.parse(“ 2002-12-15”)则引发错误。
ychaouche 2012年

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

这个答案减少了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:字符串,对象,字符串,字符串

CHROME:对象,对象,字符串,字符串


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

Typescript不是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;
}

如果有错误,则返回false。

如果没有错误,则返回json数据


4
在问题中:“解决方案不应包含try / catch”。
ddmps

1
为什么?这是保证的方式...废弃将是愚蠢的!对不起,我不懂英语。我使用了Google翻译
Emrah Tuncel,2013年

有趣。我希望看到JSON.parse与基于评估的解决方案的性能比较。但是,从安全/注入的角度来看,这看起来很可怕。
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
}

希望这可以帮助。

警告:如果有人添加了恶意的JS代码,将eval()危险,因为它将执行该代码。确保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 2010年

谢谢,但是我只是和团队一起使用,他们想要一些不使用try / catch的东西。该问题与新标题一起被编辑。对于那个很抱歉。
Chi Chan 2010年

@Mark Lutton,对象类型将不是JSON,而是XML Dom Document(我忘记了firefox中的确切类型是什么)。
Buhake Sindi'9

1
eval还接受有效的JavaScript,例如“ alert(5);”。以及单引号中的字符串,它们不是有效的JSON。
Mark Lutton 2010年

12
这纯粹是评估。
克里斯·贝克

0

哦,您绝对可以使用try catch来检查其是否为有效的JSON

在Firfox Quantom 60.0.1上测试

在函数内部使用function来测试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)不起作用。
我试图验证来自GraphiQL的 json输出,它始终返回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约定的人,这些函数返回布尔值并处理包含结果的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

非常简单的单行代码(但采用Hacky方法)

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

注意:仅当您期望某些东西是像id这样的JSON字符串时,这才有效。我将其用于API,并期望结果为JSON或某些错误字符串。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.