简体   繁体   English

如何测试字符串是否为 JSON?

[英]How to test if a string is JSON or not?

I have a simple AJAX call, and the server will return either a JSON string with useful data or an error message string produced by the PHP function mysql_error() .我有一个简单的 AJAX 调用,服务器将返回包含有用数据的 JSON 字符串或由 PHP function mysql_error()生成的错误消息字符串。 How can I test whether this data is a JSON string or the error message.如何测试此数据是 JSON 字符串还是错误消息。

It would be nice to use a function called isJSON just like you can use the function instanceof to test if something is an Array.使用名为isJSON的 function 会很好,就像您可以使用 function instanceof来测试某物是否为数组一样。

This is what I want:这就是我要的:

if (isJSON(data)){
    //do some data stuff
}else{
    //report the error
    alert(data);
}

Use JSON.parse使用 JSON.parse

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

This code is JSON.parse(1234) or JSON.parse(0) or JSON.parse(false) or JSON.parse(null) all will return true.此代码是JSON.parse(1234)JSON.parse(0)JSON.parse(false)JSON.parse(null)都将返回 true。

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

So I rewrote code in this way:所以我这样改写代码:

function isJson(item) {
    item = typeof item !== "string"
        ? JSON.stringify(item)
        : item;

    try {
        item = JSON.parse(item);
    } catch (e) {
        return false;
    }

    if (typeof item === "object" && item !== null) {
        return true;
    }

    return false;
}

Testing result:测试结果:

isJson test result isJson 测试结果

Let's recap this (for 2019+).让我们回顾一下(2019+)。

Argument : Values such as true , false , null are valid JSON (?)参数truefalsenull是有效的 JSON (?)

FACT : These primitive values are JSON-parsable but they are not well-formed JSON structure s.事实:这些原始值是JSON 可解析的,但它们不是格式良好的 JSON 结构 JSON specification indicates JSON is built on on two structures: A collection of name/value pair (object) or an ordered list of values (array). JSON 规范表明 JSON 建立在两种结构上:名称/值对(对象)的集合或值的有序列表(数组)。

Argument : Exception handling shouldn't be used to do something expected.论点:不应使用异常处理来执行预期的操作。
(This is a comment that has 25+ upvotes!) (这是一条有 25 多个赞成票的评论!)

FACT : No!事实:不! It's definitely legal to use try/catch, especially in a case like this.使用 try/catch 绝对是合法的,尤其是在这种情况下。 Otherwise, you'd need to do lots of string analysis stuff such as tokenizing / regex operations;否则,你需要做很多字符串分析的工作,比如标记/正则表达式操作; which would have terrible performance.这将有可怕的表现。

hasJsonStructure()

This is useful if your goal is to check if some data/text has proper JSON interchange format.如果您的目标是检查某些数据/文本是否具有正确的 JSON 交换格式,这将非常有用。

function hasJsonStructure(str) {
    if (typeof str !== 'string') return false;
    try {
        const result = JSON.parse(str);
        const type = Object.prototype.toString.call(result);
        return type === '[object Object]' 
            || type === '[object Array]';
    } catch (err) {
        return false;
    }
}

Usage:用法:

hasJsonStructure('true')             // —» false
hasJsonStructure('{"x":true}')       // —» true
hasJsonStructure('[1, false, null]') // —» true

safeJsonParse()

And this is useful if you want to be careful when parsing some data to a JavaScript value.如果您想在将某些数据解析为 JavaScript 值时小心谨慎,这将非常有用。

function safeJsonParse(str) {
    try {
        return [null, JSON.parse(str)];
    } catch (err) {
        return [err];
    }
}

Usage:用法:

const [err, result] = safeJsonParse('[Invalid JSON}');
if (err) {
    console.log('Failed to parse JSON: ' + err.message);
} else {
    console.log(result);
}

If the server is responding with JSON then it would have an application/json content-type, if it is responding with a plain text message then it should have a text/plain content-type.如果服务器用 JSON 响应,那么它会有一个application/json内容类型,如果它用纯文本消息响应,那么它应该有一个text/plain内容类型。 Make sure the server is responding with the correct content-type and test that.确保服务器以正确的内容类型响应并测试它。

使用jQuery $.ajax() ,如果响应是 JSON,则响应将具有responseJSON属性,可以这样测试:

if (xhr.hasOwnProperty('responseJSON')) {}
var parsedData;

try {
    parsedData = JSON.parse(data)
} catch (e) {
    // is not a valid JSON string
}

However, I will suggest to you that your http call / service should return always a data in the same format.但是,我会建议您,您的 http 调用/服务应始终以相同格式返回数据。 So if you have an error, than you should have a JSON object that wrap this error:因此,如果您有错误,那么您应该有一个包含此错误的 JSON 对象:

{"error" : { "code" : 123, "message" : "Foo not supported" } } 

And maybe use as well as HTTP status a 5xx code.并且可能使用 5xx 代码以及 HTTP 状态。

I like best answer but if it is an empty string it returns true.我喜欢最佳答案,但如果它是空字符串,则返回 true。 So here's a fix:所以这里有一个修复:

function isJSON(MyTestStr){
    try {
        var MyJSON = JSON.stringify(MyTestStr);
        var json = JSON.parse(MyJSON);
        if(typeof(MyTestStr) == 'string')
            if(MyTestStr.length == 0)
                return false;
    }
    catch(e){
        return false;
    }
    return true;
}

I use just 2 lines to perform that:我只使用 2 行来执行该操作:

var isValidJSON = true;
try { JSON.parse(jsonString) } catch { isValidJSON = false }

That's all!就这样!

But keep in mind there are 2 traps:但请记住,有两个陷阱:
1. JSON.parse(null) returns null 1. JSON.parse(null)返回null
2. Any number or string can be parsed with JSON.parse() method. 2. 任何数字或字符串都可以用JSON.parse()方法解析。
JSON.parse("5") returns 5 JSON.parse("5")返回5
JSON.parse(5) returns 5 JSON.parse(5)返回5

Let's some play on code:让我们玩一些代码:

// TEST 1
var data = '{ "a": 1 }'

// Avoiding 'null' trap! Null is confirmed as JSON.
var isValidJSON = data ? true : false
try { JSON.parse(data) } catch(e) { isValidJSON = false }

console.log("data isValidJSON: ", isValidJSON);
console.log("data isJSONArray: ", isValidJSON && JSON.parse(data).length ? true : false);

Console outputs:
data isValidJSON:  true
data isJSONArray:  false


// TEST 2
var data2 = '[{ "b": 2 }]'

var isValidJSON = data ? true : false
try { JSON.parse(data2) } catch(e) { isValidJSON = false }

console.log("data2 isValidJSON: ", isValidJSON);
console.log("data2 isJSONArray: ", isValidJSON && JSON.parse(data2).length ? true : false);

Console outputs:
data2 isValidJSON:  true
data2 isJSONArray:  true


// TEST 3
var data3 = '[{ 2 }]'

var isValidJSON = data ? true : false
try { JSON.parse(data3) } catch(e) { isValidJSON = false }

console.log("data3 isValidJSON: ", isValidJSON);
console.log("data3 isJSONArray: ", isValidJSON && JSON.parse(data3).length ? true : false);

Console outputs:
data3 isValidJSON:  false
data3 isJSONArray:  false


// TEST 4
var data4 = '2'

var isValidJSON = data ? true : false
try { JSON.parse(data4) } catch(e) { isValidJSON = false }

console.log("data4 isValidJSON: ", isValidJSON);
console.log("data4 isJSONArray: ", isValidJSON && JSON.parse(data4).length ? true : false);


Console outputs:
data4 isValidJSON:  true
data4 isJSONArray:  false


// TEST 5
var data5 = ''

var isValidJSON = data ? true : false
try { JSON.parse(data5) } catch(e) { isValidJSON = false }

console.log("data5 isValidJSON: ", isValidJSON);
console.log("data5 isJSONArray: ", isValidJSON && JSON.parse(data5).length ? true : false);


Console outputs:
data5 isValidJSON:  false
data5 isJSONArray:  false

// TEST 6
var data6; // undefined

var isValidJSON = data ? true : false
try { JSON.parse(data6) } catch(e) { isValidJSON = false }

console.log("data6 isValidJSON: ", isValidJSON);
console.log("data6 isJSONArray: ", isValidJSON && JSON.parse(data6).length ? true : false);

Console outputs:
data6 isValidJSON:  false
data6 isJSONArray:  false

Well... It depends the way you are receiving your data.嗯...这取决于您接收数据的方式。 I think the server is responding with a JSON formated string (using json_encode() in PHP,eg).我认为服务器正在使用 JSON 格式的字符串进行响应(例如,在 PHP 中使用 json_encode())。 If you're using JQuery post and set response data to be a JSON format and it is a malformed JSON, this will produce an error:如果您使用 JQuery 帖子并将响应数据设置为 JSON 格式,并且它是格式错误的 JSON,则会产生错误:

$.ajax({
  type: 'POST',
  url: 'test2.php',
  data: "data",
  success: function (response){

        //Supposing x is a JSON property...
        alert(response.x);

  },
  dataType: 'json',
  //Invalid JSON
  error: function (){ alert("error!"); }
});

But, if you're using the type response as text, you need use $.parseJSON.但是,如果您将类型响应用作文本,则需要使用 $.parseJSON。 According jquery site: "Passing in a malformed JSON string may result in an exception being thrown".根据 jquery 站点:“传入格式错误的 JSON 字符串可能会导致抛出异常”。 Thus your code will be:因此,您的代码将是:

$.ajax({
  type: 'POST',
  url: 'test2.php',
  data: "data",
  success: function (response){

        try {
            parsedData = JSON.parse(response);
        } catch (e) {
            // is not a valid JSON string
        }

  },
  dataType: 'text',
});

There are probably tests you can do, for instance if you know that the JSON returned is always going to be surrounded by { and } then you could test for those characters, or some other hacky method.您可能可以进行一些测试,例如,如果您知道返回的 JSON 总是会被{}包围,那么您可以测试这些字符或其他一些hacky 方法。 Or you could use the json.org JS library to try and parse it and test if it succeeds.或者你可以使用json.org JS 库来尝试解析它并测试它是否成功。

I would however suggest a different approach.但是,我建议采用不同的方法。 Your PHP script currently returns JSON if the call is successful, but something else if it is not.如果调用成功,您的 PHP 脚本当前返回 JSON,否则返回其他内容。 Why not always return JSON?为什么不总是返回 JSON?

Eg例如

Successful call:调用成功:

{ "status": "success", "data": [ <your data here> ] }

Erroneous call:错误调用:

{ "status": "error", "error": "Database not found" }

This would make writing your client side JS much easier - all you have to do is check the "status" member and the act accordingly.这将使编写您的客户端 JS 变得更加容易——您所要做的就是检查“状态”成员并相应地采取行动。

Here is a code with some minor modification in Bourne's answer.这是对 Bourne 的回答进行了一些小的修改的代码。 As JSON.parse(number) works fine without any exception so added isNaN.由于 JSON.parse(number) 工作正常,没有任何异常,所以添加了 isNaN。

function isJson(str) {
    try {
        JSON.parse(str);
    } catch (e) {
        return false;
    }
    return isNaN(str);
}

All json strings start with '{' or '[' and end with the corresponding '}' or ']', so just check for that.所有 json 字符串都以 '{' 或 '[' 开头,并以相应的 '}' 或 ']' 结尾,所以只需检查一下。

Here's how Angular.js does it:下面是 Angular.js 如何做到的:

var JSON_START = /^\[|^\{(?!\{)/;
var JSON_ENDS = {
  '[': /]$/,
  '{': /}$/
};

function isJsonLike(str) {
    var jsonStart = str.match(JSON_START);
    return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
}

https://github.com/angular/angular.js/blob/v1.6.x/src/ng/http.js https://github.com/angular/angular.js/blob/v1.6.x/src/ng/http.js

I used this one (kind of mix of different answers, but anyway):我使用了这个(混合了不同的答案,但无论如何):

 const isJSON = str => { if (typeof str === 'string'){ try { JSON.parse(str) return true } catch(e){ } } return false } [null, undefined, false, true, [], {}, '', 'asdf', '{}', '[]', "{\\"abc\\": 2}","{\\"abc\\": \\"2\\"}"] .map(el => { console.log(`[>${el}<] - ${isJSON(el)}`) }) console.log('-----------------')

Warning: For methods relying on JSON.parse - Arrays and quote surrounded strings will pass too (ie. console.log(JSON.parse('[3]'), JSON.parse('"\?"')) )警告:对于依赖JSON.parse方法 - 数组和引号包围的字符串也将通过(即console.log(JSON.parse('[3]'), JSON.parse('"\?"'))

To avoid all non-object JSON primitives (boolean, null, array, number, string), I suggest using the following:为了避免所有非对象 JSON 原语(布尔值、空值、数组、数字、字符串),我建议使用以下内容:

/* Validate a possible object ie. o = { "a": 2 } */
const isJSONObject = (o) => 
  !!o && (typeof o === 'object') && !Array.isArray(o) && 
  (() => { try { return Boolean(JSON.stringify(o)); } catch { return false } })()

/* Validate a possible JSON object represented as string ie. s = '{ "a": 3 }' */
function isJSONObjectString(s) {
    try {
        const o = JSON.parse(s);
        return !!o && (typeof o === 'object') && !Array.isArray(o)
    } catch {
        return false
    }
}

Code Explanation代码说明

  • !!o - Not falsy (excludes null, which registers as typeof 'object') !!o - 不假(不包括 null,它注册为 typeof 'object')
  • (typeof o === 'object') - Excludes boolean, number, and string (typeof o === 'object') - 排除布尔值、数字和字符串
  • !Array.isArray(o) - Exclude arrays (which register as typeof 'object') !Array.isArray(o) - 排除数组(注册为 typeof 'object')
  • try ... JSON.stringify / JSON.parse - Asks JavaScript engine to determine if valid JSON try ... JSON.stringify / JSON.parse - 要求 JavaScript 引擎确定 JSON 是否有效

Why not use the hasJsonStructure() answer?为什么不使用 hasJsonStructure() 答案?

Relying on toString() is not a good idea.依赖toString()不是一个好主意。 This is because different JavaScript Engines may return a different string representation.这是因为不同的 JavaScript 引擎可能返回不同的字符串表示。 In general, methods which rely on this may fail in different environments or may be subject to fail later should the engine ever change the string result通常,依赖于此的方法可能会在不同的环境中失败,或者如果引擎更改字符串结果,则以后可能会失败

Why is catching an exception not a hack?为什么捕获异常不是黑客攻击?

It was brought up that catching an exception to determine something's validity is never the right way to go.有人提出,捕捉异常来确定某事的有效性从来都不是正确的方法。 This is generally good advice, but not always.这通常是很好的建议,但并非总是如此。 In this case, exception catching is likely is the best route because it relies on the JavaScript engine's implementation of validating JSON data.在这种情况下,异常捕获可能是最佳途径,因为它依赖于 JavaScript 引擎对 JSON 数据进行验证的实现。

Relying on the JS engine offers the following advantages:依靠JS引擎提供以下优势:

  1. More thorough and continually up-to-date as JSON spec changes随着 JSON 规范的变化,更加全面和持续更新
  2. Likely to run faster (as it's lower level code)可能运行得更快(因为它是较低级别的代码)

When given the opportunity to lean on the JavaScript engine, I'd suggest doing it.当有机会依靠 JavaScript 引擎时,我建议这样做。 Particularly so in this case.在这种情况下尤其如此。 Although it may feel hacky to catch an exception, you're really just handling two possible return states from an external method.尽管捕获异常可能会让人感觉很棘手,但您实际上只是在处理来自外部方法的两种可能的返回状态。

You could try decoding it and catching the exception (native or json2.js ):您可以尝试对其进行解码并捕获异常(本机或json2.js ):

try {
  newObj = JSON.parse(myJsonString);
} catch (e) {
  console.log('Not JSON');
}

However, I would suggest making the response always be valid JSON.但是,我建议使响应始终是有效的 JSON。 If you get an error back from your MySQL query, simply send back JSON with the error:如果您从 MySQL 查询返回错误,只需发送带有错误的 JSON:

{"error":"The MySQL error string."}

And then:进而:

if (myParsedJSON.error) {
  console.log('An error occurred: ' + myParsedJSON.error);
}

I suggest in Typescript mode: 我建议在打字稿模式下:

export function stringify(data: any): string {
    try {
         return JSON.stringify(data)
    } catch (e) {
         return 'NOT_STRINGIFIABLE!'
    }
}

You can try the following one because it also validates number, null, string but the above-marked answer is not working correctly it's just a fix of the above function:您可以尝试以下方法,因为它还可以验证数字、空值、字符串,但上面标记的答案无法正常工作,它只是对上述功能的修复:

function isJson(str) {
  try {
      const obj = JSON.parse(str);
      if (obj && typeof obj === `object`) {
        return true;
      }
    } catch (err) {
      return false;
    }
   return false;
}

I think something like following method should do the job, it returns the parsed JSON (in case of valid JSON), so you don't need to call the JSON.parse again.我认为类似下面的方法应该可以完成这项工作,它返回解析的 JSON(在有效 JSON 的情况下),因此您不需要再次调用JSON.parse

const tryParseJSON = (s) => {
    if (!s) return false;

    try {
        var o = JSON.parse(s);
        if (o && typeof o === "object") return o;
    }
    catch (e) { }

    return false;
};

If you don't mind lodash如果你不介意lodash

npm i -S lodash

const isPlainObject = require("lodash/isPlainObject"); // cjs
// import {isPlainObject} from "lodash"; // esm
function checkIfJSON(input) {
  const inputStr = typeof input === "string" ? input : JSON.stringify(input);
  try {
    if (isPlainObject(JSON.parse(inputStr))) {
      return true;
    }
  } catch (e) {
    return false;
  }
}

For me I simply did this just by 2 positive returned condition,对我来说,我只是通过 2 个正返回条件做到了这一点,

First Condition - Check if the both ends are "{" and "}"第一个条件- 检查两端是否为“{”和“}”

Second Condition - Check if it is parsable by JSON第二个条件- 检查它是否可以被 JSON 解析

here how I did it我是怎么做到的

const isJsonStringified = (value) => {
  try {
    const isObject = value.slice(0, 1) === '{' && value.slice(value.length - 1) === '}';
    if (typeof value === 'string' && isObject) {
      JSON.parse(value);
    } else {
      return false;
    }
  } catch (err) {
    return false;
  }
  return true;
};

Welcome :)欢迎 :)

Numbers and boolean values are accepted as valid json in JSON.parse(), just add type validations before parsing数字和boolean值在JSON.parse()中被接受为有效的json,只需在解析前添加类型验证

function isJson(str) {

    if(!isNaN(str) || str.toString() == 'true' || str.toString() == 'false'){
        return false;
    }

    try {

        JSON.parse(str);

    } catch (e) {

        return false;

    }

    return true;

}

 export function isJsonString(value) { try { return typeof JSON.parse(value) === 'object'; } catch (e) { return false; } }

This handled most of the required cases for me!这为我处理了大部分必需的案例!

In addition to previous answers, in case of you need to validate a JSON format like "{}", you can use the following code:除了之前的答案,如果您需要验证像“{}”这样的 JSON 格式,您可以使用以下代码:

const validateJSON = (str) => {
  try {
    const json = JSON.parse(str);
    if (Object.prototype.toString.call(json).slice(8,-1) !== 'Object') {
      return false;
    }
  } catch (e) {
    return false;
  }
  return true;
}

Examples of usage:用法示例:

validateJSON('{}')
true
validateJSON('[]')
false
validateJSON('')
false
validateJSON('2134')
false
validateJSON('{ "Id": 1, "Name": "Coke" }')
true

The answers above are quite okay but JSON.parse is said to be expensive, so you most likely will want to retain the parsed data just in-case it passes, rather than parsing again. 上面的答案是相当不错的,但JSON.parse据说是昂贵的,所以你很可能只想保留解析后的数据,而不是再次解析。

function isJson(str) {
    if (typeof str !== "string" || `${str}`.length === 0) return [false, str];
    let json = "";
    let isValid = false;
    try {
        json = JSON.parse(str);
        isValid = true;
    } catch (e) {
        isValid = false
    }
    if (!json || typeof json !== "object") isValid = false;
    return [isValid, json]
};

//Usage
const [isValid, json] = isJson("[\"abc\", \"123\"]");
if(isValid) console.log(json);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM