文字列がJSONかどうかをテストするにはどうすればよいですか?


191

私は単純なAJAX呼び出しを行っており、サーバーは有用なデータを含むJSON文字列か、PHP関数によって生成されたエラーメッセージ文字列を返しますmysql_error()。このデータがJSON文字列かエラーメッセージかをテストするにはどうすればよいですか。

何かが配列であるかどうかをテストisJSONするために関数instanceofを使用できるのと同じように呼び出される関数を使用するとよいでしょう。

これが私が欲しいものです:

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

多分eval()それが返すならそれを使うかもしれundefinedませんが、それはJSONではありません
MatuDuke

4
これは、ここで解決されている:stackoverflow.com/questions/3710204/...
Reinardを

2
みんなに感謝します。申し訳ありませんが、他の投稿は以前には見つかりませんでした。
jeffery_the_wind 2012年

1
技術的にはこれは3710204のだましではありません。それは、jsonよりもはるかに高いバーである有効なjsonであるかどうかを尋ねるからです。
carlin.scott

回答:


319

JSON.parseを使用する

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

53
例外処理は、期待された何かをするために使用されるべきではありません。
luisZavaleta 2015

44
JSON.parse(1234)OR JSON.parse(0)OR JSON.parse(false)OR JSON.parse(null)すべては例外を発生させず、true !!を返します。この回答は使用しないでください
Zalaboza '12 / 09/15

19
@Zalaboza 12340false、およびnullすべての有効なJSON値です。JSONがオブジェクトを表すかどうかをテストする述語が必要な場合は、もう少し行う必要があります。
マイケルラング

20
JSON.parse文字列を解析するために多くの計算を行い、成功した場合はjsonオブジェクトを提供しますが、一部のユーザーが使用する可能性のある結果を破棄しています。それは良くないようです。代わりreturn {value: JSON.parse(str), valid: true};に、catchブロックでreturn {value: str, valid: false};、関数名をに変更しますtryParse()
Nawaz、2016年

7
@luisZavaletaでは、メソッドとして何を提案しますか
PirateApp

80

このコードはJSON.parse(1234)orまたはJSON.parse(0)or JSON.parse(false)またはJSON.parse(null)allはtrueを返します。

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

だから私はこのようにコードを書き直しました:

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

テスト結果:

isJsonテスト結果


4
よくやった!あなたの最後の文は、次のような単純なreturn文に単純化することができれば:return (typeof suspect === "object" && suspect !== null);
Nebulosar

38

これを要約してみましょう(2019年以降)。

引数:値は、次のようなtruefalsenullJSON有効です(?)

FACT:これらのプリミティブ値はJSONで解析可能ですが、整形式のJSON構造ではありません。JSON 仕様は、JSONが2つの構造に基づいて構築されていることを示しています。名前と値のペアのコレクション(オブジェクト)または値の順序付きリスト(配列)。

引数:例外処理を使用して、期待されていることを行うべきではありません。
(これは25以上の投票があるコメントです!)

事実:いいえ!特にこのような場合、try / catchを使用することは間違いなく合法です。それ以外の場合は、トークン化や正規表現の操作など、多くの文字列分析を行う必要があります。ひどいパフォーマンスになるでしょう。

hasJsonStructure()

これは、一部のデータ/テキストが適切な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;
    }
}

使用法:

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

safeJsonParse()

これは、一部のデータをJavaScript値に解析するときに注意が必要な場合に役立ちます。

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

使用法:

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

1
JSON仕様にリンクすると、「JSONテキストは、JSON値の文法に準拠するUnicodeコードポイントから形成される一連のトークンです。」および「JSON値は、オブジェクト、配列、数値、文字列、true、false、またはnullにすることができます。」-JSONはルートレベルでのみオブジェクトまたは配列である可能性があるという結論にどのように到達しましたか?私はこれを仕様で見ることも、「整形式のJSON構造」についても何もわかりません
Relequestual

始まっていること第二段落読む「JSONは二つの構造の上に構築されているが...」@ json.orgかの4番目と5番目の段落ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
オヌルユルドゥルム

json.orgは情報提供のみを目的としています。リンクした仕様を読んでも、提案はサポートされません。仕様では、RFC 8259が最新のRFCとして言及されています。値のみを含む有効なJSON texの例を見てください。tools.ietf.org/html/rfc8259#section - 13-このように、RFC 8259は考えられるあいまいさと混乱を解決するように設計されています。
Relequestual

もう一度答えを読んでください。プリミティブなどの値(つまり、RFCの例ではテキスト値)はJSONの「構造」ではないと言っています。あいまいさはありません。JSONとして解析できますが、そうすることは有効です。ただし、構造化されたデータではありません。JSONは、主にオブジェクトまたは配列である»構造化データに使用される»交換フォーマットとして発明されました。
OnurYıldırım19年

1
はい、そう思います。プリミティブは仕様に従って有効なJSONですが、「構造」ではありません。それはいいです。しかし、「引数:true、false、nullなどの値は有効なJSON(?)です。事実:はい、いいえ!」-実際には、仕様に従って有効なJSONです。それらが有用かどうかについての意見は、その事実とは無関係です。
Relequestual

20

サーバーがJSONで応答している場合は、application/jsonコンテンツタイプがあり、プレーンテキストメッセージで応答している場合は、text/plainコンテンツタイプが必要です。サーバーが正しいコンテンツタイプで応答していることを確認し、それをテストします。


4
これは間違っています。json互換のメディアタイプは他にもたくさんあります。さらにoverrideMimeType、content-typeヘッダーをオーバーライドできます。
KNU

13

応答がJSONの場合、応答を使用jQuery $.ajax()するときにresponseJSONプロパティが含まれます。これは次のように確認できます。

if (xhr.hasOwnProperty('responseJSON')) {}

2
これは、おそらくOPでさえ、ほとんどの人が探している答えであり、おそらくOP
Kirby

これは、try catchブロックを使用するよりもはるかにエレガントです
Anurag Sinha

6

私はベストアンサーが好きですが、空の文字列の場合はtrueを返します。だからここに修正があります:

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

var jsonは使用されませんか?またはエラーをキャッチするだけですか?
stackdave 2017

5
var parsedData;

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

ただし、http呼び出し/サービスが常に同じ形式のデータを返すようにすることをお勧めします。したがって、エラーが発生した場合は、このエラーをラップするJSONオブジェクトが必要です。

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

また、HTTPステータスだけでなく5xxコードも使用できます。


5

まあ...それはあなたがあなたのデータを受け取る方法に依存します。サーバーはJSON形式の文字列(PHPでjson_encode()を使用するなど)で応答していると思います。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!"); }
});

ただし、タイプレスポンスをテキストとして使用する場合は、$。parseJSONを使用する必要があります。jqueryサイトによると:「不正な形式のJSON文字列を渡すと、例外がスローされる場合があります」。したがって、コードは次のようになります。

$.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',
});

もちろん、上記の例のエラー関数のエラーテキストを解析しようとしていて、それがJSONかどうかわからない場合を除きます
Kirby

正解responseです。空の場合は、次のようになりますsuccess: '(
Henrik Petterson

4

実行できるテストはおそらくあるでしょう。たとえば、返されたJSONが常に囲まれ{}、あなたはそれらの文字のためにテストすることができ、または他のいくつかのハック方法が。または、json.orgを使用することもできます JSライブラリをそれを解析して、成功するかどうかをテストすること。

ただし、別のアプローチをお勧めします。現在、PHPスクリプトは、呼び出しが成功した場合にJSONを返しますが、そうでない場合は何かを返します。なぜいつもではない JSON返さですか?

例えば

成功した呼び出し:

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

誤った呼び出し:

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

これにより、クライアント側のJSの記述がはるかに簡単になります。「ステータス」メンバーとそれに応じた動作を確認するだけです。


4

私はそれを実行するために2行だけを使います:

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

それで全部です!

ただし、2つのトラップがあることに注意してください
。1. JSON.parse(null)戻り値null
2. JSON.parse()メソッドを使用して、任意の数値または文字列を解析できます。
   JSON.parse("5")リターンズ5
   JSON.parse(5)リターンズ5

コードで遊んでみましょう:

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

私はjsfiddle.net/fatmonk/gpn4eyavでこの回答のフィドルを作成しました。これには、独自のユーザーテストデータを追加するオプションも含まれています。これは良いライブラリ関数の基礎のように見えますが、なぜTest 1が有効なJSON配列ではないのかについてもっと理解したいと思います。
Fat Monk

[とを使用して配列を指定する必要があるため]です。たとえば、[1, 2, 3]は数値配列です。["a", "b", "c"]文字列配列です。そして[{"a":1}, {"b":2}]JSON配列です。あなたのjsfiddleの作業は本当に役立つようです!
efkan 2017年

そんなに簡単?したがって、テスト1はJSONオブジェクトであり、テスト2は単一のJSONオブジェクト要素で構成されるJSON配列です。私はそれを正しく理解しましたか?
Fat Monk

これの可能性のある重複としてフラグが付けられた質問(stackoverflow.com/questions/3710204/…)は、try / catchを使用せずにこれを達成することについて尋ねるので、私はフィドルをフォークしてその目標を達成しようと試みました。フォークはjsfiddle.net/fatmonk/827jsuvrにあり、テスト3を除いて上記のすべてのテストで機能しますJSON.parse。誰かがtryを使わずにそのエラーを回避する方法をアドバイスできますか?
Fat Monk

あなたのjsfiddleアプリケーションは、有効なJSON表現を持っていないので、テスト3のエラーがスローされます。だからtry-catch:そのエラーをキャッチすると、上記のテスト3のように解析するとき式はJSONではないとして、エラーを評価するために使用されなければならないtry { JSON.parse(data3) } catch(e) { isValidJSON = false }
efkan

2

あなたはそれをデコードして例外をキャッチしてみることができます(ネイティブまたはjson2.js):

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

ただし、応答を常に有効なJSONにすることをお勧めします。MySQLクエリからエラーが返された場合は、JSONをエラーとともに送信します。

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

その後:

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

2

警告:依存するメソッドの場合JSON.parse-配列と引用符で囲まれた文字列も渡されます(つまり、console.log(JSON.parse('[3]'), JSON.parse('"\uD800"'))

オブジェクト以外のすべてのJSONプリミティブ(ブール値、null、配列、数値、文字列)を回避するには、以下を使用することをお勧めします。

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

コード説明

  • !! o偽物ではありません(typeof 'object'として登録されるnullは除く)
  • (typeof o === 'オブジェクト') -ブール値、数値、文字列を除外します
  • !Array.isArray(o)-配列を除外(typeof 'object'として登録)
  • try ... JSON.stringify / JSON.parse-有効なJSONかどうかを判断するようJavaScriptエンジンに要求します

hasJsonStructure()回答を使用しないのはなぜですか?

に依存しています toString()は良い考えはありません。これは、異なるJavaScriptエンジンが異なる文字列表現を返す可能性があるためです。一般に、これに依存するメソッドは、異なる環境で失敗するか、エンジンが文字列の結果を変更した場合に後で失敗する可能性があります

なぜハックではなく例外をキャッチするのですか?

何かの妥当性を判断するために例外をキャッチすることは、正しい方法では決してないことが提起されました。これは一般的には良いアドバイスですが、常にではありません。この場合、JavaScriptエンジンによるJSONデータの検証の実装に依存しているため、例外のキャッチがおそらく最適なルートです。

JSエンジンを使用すると、次の利点があります。

  1. JSON仕様の変更に伴う、より徹底的かつ継続的な最新情報
  2. より高速に実行される可能性が高い(低レベルのコードであるため)

JavaScriptエンジンに頼る機会が与えられたら、私はそれを実行することをお勧めします。特にこの場合はそうです。例外をキャッチするの面倒に感じるかもしれませんが、実際には、外部メソッドから返される可能性のある2つの状態を処理しているだけです。


1

以下は、ボーンの回答に若干の変更を加えたコードです。JSON.parse(number)は例外なく正常に動作するため、isNaNが追加されました。

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

0

すべてのjson文字列は '{'または '['で始まり、対応する '}'または ']'で終わるので、それを確認してください。

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


@DukeDougal明確にする必要がありますか?人々はjsonを '['で始めますが、それはそれほど一般的ではありません。
carlin.scott

1
有効なJSONで動作するように解析する必要があります。それが無効なJSONである場合、それはJSONではありません。問題は、「文字列がJSONかどうかをどのように判断するか」です。あなたのアプローチでは、これはJSON {fibble-であり、実際にはJSONではありません。数値1のような場合も考慮してください-それは有効なJSONです。
デュークドゥーガル2016年

1
「JSONが無効な場合、JSONではありません」。「有効」という単語を使用する必要があるという事実は、それが単なるjsonだけではないという事実に資格を追加していることを示しています。質問は単に「それはjsonですか」でした。私のコード例は、追加の要件を想定せずにその質問に完全に回答します。
carlin.scott

一部のテンプレートシステムを使用していて、{ someValue }自動的に検証に合格するようなものがある場合、悪い考えです。
ncubica 2016

@ncubicaでは、json以外のテンプレートを使用しています。文字列には中括弧を使用するプレースホルダーのみが含まれており、テンプレートエンジンはプレースホルダーを実際の値に置き換えられませんか?また、すでにデュークに説明したように、元の質問では検証については触れられていません。彼らはそれがjsonのように見えるかどうかを知りたかっただけです。
carlin.scott

0

私はTypescriptモードで提案します:

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

0

私はこれを使用しました(さまざまな回答の一種ですが、とにかく):

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('-----------------')


0

次のコードも試すことができます。数値、null、文字列も検証されますが、上記の回答が正しく機能しないため、上記の関数の修正にすぎません。

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

-1

以前の回答に加えて、「{}」のような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;
}

使用例:

validateJSON('{}')
true
validateJSON('[]')
false
validateJSON('')
false
validateJSON('2134')
false
validateJSON('{ "Id": 1, "Name": "Coke" }')
true
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.