Bir dizenin JSON olup olmadığını nasıl test edebilirim?


191

Basit bir AJAX çağrısı var ve sunucu yararlı verileri ile bir JSON dize veya PHP işlevi tarafından üretilen bir hata iletisi dizesi dönecektir mysql_error(). Bu verilerin bir JSON dizesi mi yoksa hata mesajı mı olduğunu nasıl test edebilirim?

Bir şeyin Dizi olup olmadığını test etmek isJSONiçin işlevi kullanabileceğiniz gibi adlandırılan bir işlevi kullanmak iyi olurdu instanceof.

İstediğim bu:

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

Belki eval()o zaman dönerse kullanmak undefinedJSON değil
MatuDuke

4
Bu, burada çözülmüştür: stackoverflow.com/questions/3710204/…
Reinard

2
Herkese teşekkürler, daha önce başka bir yazı bulamadım.
jeffery_the_wind

1
Teknik olarak, bu 3710204'lük bir dupe değildir, çünkü geçerli bir json olup olmadığını sorar, ki bu da geçmek için çok daha yüksek bir çubuktur.
carlin.scott

Yanıtlar:


324

JSON.parse kullanın

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

53
İstisna yönetimi beklenen bir şeyi yapmak için kullanılmamalıdır.
luisZavaleta

46
JSON.parse(1234)VEYA VEYA JSON.parse(0)VEYA JSON.parse(false)VEYA JSON.parse(null)hepsi İstisna yükseltmeyecek ve gerçek dönecektir !!. bu yanıtı kullanma
Zalaboza

19
@Zalaboza 1234, 0, falseve nulltüm geçerli JSON değerleridir. JSON'un bir nesneyi temsil edip etmediğini test eden bir yüklem istiyorsanız, biraz daha yapmanız gerekir.
Michael Lang

20
JSON.parsedizeyi ayrıştırmak için çok sayıda hesaplama yapar ve başarılı olursa json nesnesini verir, ancak bazı kullanıcıların kullanmak isteyebileceği sonucu atarsınız. Bu iyi görünmüyor. Bunun yerine return {value: JSON.parse(str), valid: true};ve catch bloğunda return {value: str, valid: false};.. ve fonksiyon adını olarak değiştirirdim tryParse().
Nawaz

7
@luisZavaleta o zaman bir yöntem olarak ne öneriyorsunuz
PirateApp

80

Bu kod JSON.parse(1234)ya da JSON.parse(0)ya JSON.parse(false)da JSON.parse(null)tümü doğru olacaktır.

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

Bu yüzden kodu bu şekilde yeniden yazdım:

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

Test sonucu:

isJson test sonucu


4
İyi iş! Son if return (typeof suspect === "object" && suspect !== null);
ifadeniz aşağıdaki

39

Bunu özetleyelim (2019+ için).

Argüman : true,, falsegibi nulldeğerler geçerli JSON (?)

GERÇEK : Bu ilkel değerler JSON ile ayrıştırılabilir ancak iyi biçimlendirilmiş JSON yapıları değildir . JSON belirtimi , JSON'un iki yapı üzerine kurulu olduğunu gösterir: Bir ad / değer çifti (nesne) koleksiyonu veya sıralı değerler listesi (dizi).

Argüman : İstisna işleme beklenen bir şeyi yapmak için kullanılmamalıdır.
(Bu, 25'ten fazla oy içeren bir yorumdur!)

GERÇEK : Hayır! Özellikle böyle bir durumda try / catch kullanmak kesinlikle yasaldır. Aksi takdirde, tokenize etme / regex işlemleri gibi birçok dize analizi öğesi yapmanız gerekir; bu korkunç bir performansa sahip olurdu.

hasJsonStructure()

Amacınız bazı verilerin / metnin uygun JSON değişim biçimine sahip olup olmadığını kontrol etmekse yararlıdır.

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

Kullanımı:

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

safeJsonParse()

Bazı verileri bir JavaScript değerine ayrıştırırken dikkatli olmak istiyorsanız bu yararlıdır.

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

Kullanımı:

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

1
JSON Spec'e şu bağlantıyı veriyorsunuz: "JSON metni, Unicode kod noktalarından oluşturulan ve JSON değeri dilbilgisine uyan belirteç dizisidir." ve "Bir JSON değeri bir nesne, dizi, sayı, dize, true, false veya null olabilir." - Bir JSON'un yalnızca kök düzeyinde nesne veya dizi olabileceği sonucuna nasıl vardınız? Ne spec göremiyorum, ne de "iyi biçimlendirilmiş JSON yapıları" ile ilgili bir şey
Relequestual

İle başlar, ikinci paragraf oku "JSON iki yapı üzerine inşa edilmiştir ..." @ json.org veya 4. ve 5. paragrafları ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
Onur Yıldırım

json.org yalnızca bilgilendiricidir. Bağlantı verdiğiniz spesifikasyonu okumak önerinizi desteklemiyor. Spesifikasyon en son RFC olarak RFC 8259'dan bahsediyor. Yalnızca değerler içeren geçerli JSON metinlerine bir göz atın tools.ietf.org/html/rfc8259#section-13 - RFC 8259, bunun gibi olası belirsizlikleri ve karışıklıkları çözmek için tasarlanmıştır.
Relequestual

Cevabı tekrar okuyun. Ben ilkel (örneğin RFC örneklerinde metin değerleri) gibi değerler JSON "yapı" s değil diyorum. Belirsizlik yok. Bunları JSON olarak ayrıştırabilirsiniz, bunu yapmak geçerlidir. Ancak bunlar yapılandırılmış veriler değildir. JSON temel olarak bir nesne veya dizi olabilen »yapılandırılmış veriler için kullanılan» bir değişim biçimi olarak icat edilir.
Onur Yıldırım

1
Tamam, sanırım kabul ediyoruz. İlkeler spesifikasyona göre geçerli JSON'dur, ancak "yapılar" değildir. Bu iyi. Ancak, "Argüman: true, false, null gibi değerler geçerli JSON (?). Gerçek: Evet ve hayır!" - Gerçek şu ki, spesifikasyona göre ARE geçerli JSON. Yararlı olup olmadıklarına ilişkin görüşler bu gerçeğe ilişkin değildir.
Relequestual

20

Sunucu JSON ile yanıt veriyorsa, application/jsoniçerik türüne sahip olacaktır, düz metin mesajıyla yanıt veriyorsa text/plainiçerik türüne sahip olmalıdır . Sunucunun doğru içerik türüyle yanıt verdiğinden emin olun ve bunu test edin.


4
Bu yanlış, json uyumlu başka birçok mediatip var. Ayrıca overrideMimeType, içerik türü üstbilgisini geçersiz kılabilir.
Knu

14

yanıt JSON ise, yanıtın kullanılması jQuery $.ajax()özelliğe sahip responseJSONolduğunda, bu şu şekilde kontrol edilebilir:

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

3
Bu şüpheli gerçekten çoğu insanın aradığı cevap, muhtemelen OP
Kirby

1
Bu, try catch bloğunu kullanmaktan çok daha zarif
Anurag Sinha

6

En iyi yanıtı seviyorum ama boş bir dize ise doğru döner. İşte bir düzeltme:

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 kullanılmaz mı? ya da sadece hatayı yakalamak için?
stackdave

5
var parsedData;

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

Ancak, http aramanızın / hizmetinizin her zaman aynı biçimde bir veri döndürmesi gerektiğini size önereceğim. Eğer bir hatanız varsa, bu hatayı saran bir JSON nesneniz olmalıdır:

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

Ve belki de HTTP durumu 5xx kodu kullanın.


5

Şey ... Verilerinizi alma şeklinize bağlıdır. Sunucu (örneğin PHP, json_encode () kullanarak) JSON biçimli bir dize ile yanıt düşünüyorum. JQuery yayını kullanıyorsanız ve yanıt verilerini bir JSON biçimi olarak ayarlarsanız ve hatalı biçimlendirilmiş bir JSON ise, bu bir hata oluşturur:

$.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!"); }
});

Ancak, tür yanıtını metin olarak kullanıyorsanız, $ .parseJSON kullanmanız gerekir. Jquery sitesine göre: "Hatalı biçimlendirilmiş bir JSON dizesinde geçmek bir istisna oluşmasına neden olabilir". Böylece kodunuz:

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

sürece, tabii ki yukarıdaki örnekte hata fonksiyonunda hata metnini ayrıştırmak ve JSON olup olmadığından emin değilseniz ...
Kirby

Büyük cevap, responseboş olsa da , şu şekilde gidecek success: '(
Henrik Petterson

4

Muhtemelen yapabileceğiniz testler vardır, örneğin, döndürülen JSON'un her zaman çevreleneceğini biliyorsanız {ve }bu karakterleri veya başka bir hacky yöntemini test edebilirsiniz. Veya json.org'u kullanabilirsiniz JS kütüphanesini kullanarak denemek ve ayrıştırıp başarılı olup olmadığını test etmek için kullanabilirsiniz.

Ancak farklı bir yaklaşım öneririm. PHP betiğiniz şu anda çağrı başarılıysa JSON, ancak değilse başka bir şey döndürür. Neden her zaman olmasın JSON döndürmüyorsunuz?

Örneğin

Başarılı çağrı:

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

Hatalı çağrı:

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

Bu, istemci tarafı JS'nizi yazmayı çok daha kolay hale getirir - tek yapmanız gereken "durum" üyesini ve buna göre davranışı kontrol etmektir.


4

Bunu yapmak için sadece 2 satır kullanıyorum:

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

Bu kadar!

Ancak 2 tuzak olduğunu unutmayın:
1. JSON.parse(null)döndürür null
2. Herhangi bir sayı veya dize JSON.parse()yöntemi ile ayrıştırılabilir .
   JSON.parse("5")döner 5
   JSON.parse(5)döner5

Hadi kodda oynayalım:

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

Bu cevap için kendi kullanıcı test verilerinizi de ekleme seçeneğini içeren jsfiddle.net/fatmonk/gpn4eyav adresinde bir keman oluşturdum . Bu benim için iyi bir kütüphane fonksiyonunun temeli gibi görünüyor, ancak Test 1'in neden geçerli bir JSON dizisi olmadığı hakkında daha fazla bilgi edinmek istiyorum.
Şişman Keşiş

Çünkü bir dizi [ve kullanılarak belirtilmelidir ]. Örneğin [1, 2, 3], bir sayı dizisidir. ["a", "b", "c"]bir dize dizisidir. Ve [{"a":1}, {"b":2}]bir JSON dizisidir. Jsfiddle çalışmanız gerçekten yararlı görünüyor!
efkan

Kadar basit?! Test 1 bir JSON nesnesidir ve Test 2, tek bir JSON nesne öğesinden oluşan bir JSON dizisidir. Bunu doğru anladım mı?
Şişman Keşiş

Bunun olası bir kopyası olarak işaretlenen soru ( stackoverflow.com/questions/3710204/… ) try / catch kullanmadan bunu başarmayı ister , bu yüzden de bu hedefe ulaşmaya çalıştım. Çatal jsfiddle.net/fatmonk/827jsuvr adresindedir ve Test 3 dışındaki hatalarda yukarıdaki tüm testlerle çalışır JSON.parse. Deneme kullanmadan bu hatayı nasıl önleyeceğinizi önerebilir misiniz?
Şişman Keşiş

Kişisel jsfiddlebaşvuru geçerli bir JSON ifadesini olmadığı için Testi 3 hata verir. Yani try-catchbu hatayı yakalamak ve yukarıdaki Test 3 gibi ayrıştırırken ifade JSON olmadığından herhangi bir hatayı değerlendirmek için kullanılmalıdır:try { JSON.parse(data3) } catch(e) { isValidJSON = false }
efkan

2

Kod çözmeyi ve istisnayı yakalamayı deneyebilirsiniz (yerli veya json2.js ):

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

Ancak, yanıtın her zaman geçerli JSON olmasını öneririm. MySQL sorgunuzdan bir hata alırsanız, JSON hatasını geri gönderin:

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

Ve sonra:

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

2

Uyarı: Güvenilen yöntemler için JSON.parse- Diziler ve tırnak içine alınmış dizeler de geçecektir (ör. console.log(JSON.parse('[3]'), JSON.parse('"\uD800"')))

Nesne olmayan tüm JSON ilkellerinden (boolean, null, dizi, sayı, dize) kaçınmak için aşağıdakileri kullanmanızı öneririm:

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

Kod Açıklaması

  • !! o - Yanlış değil ('nesne' türünü kaydeden null değeri hariç)
  • (typeof o === 'object') - Boole, sayı ve dizeyi hariç tutar
  • ! Array.isArray (o) - Dizileri hariç tut ('nesne' typeof olarak kaydedilir)
  • deneyin ... JSON.stringify / JSON.parse - JavaScript motorundan geçerli JSON olup olmadığını belirlemesini ister

Neden hasJsonStructure () yanıtını kullanmıyorsunuz?

Güvenen toString() iyi bir fikir değil. Bunun nedeni, farklı JavaScript Motorlarının farklı bir dize gösterimi döndürebilmesidir. Genel olarak, buna güvenen yöntemler farklı ortamlarda başarısız olabilir veya motor dize sonucunu değiştirirse daha sonra başarısız olabilir.

Neden bir istisna yakalamak bir hack değil?

Bir şeyin geçerliliğini belirlemek için bir istisna yakalamak asla doğru yol değildir. Bu genellikle iyi bir tavsiye, ama her zaman değil. Bu durumda, JavaScript motorunun JSON verilerini doğrulama uygulamasına dayandığından istisna yakalama muhtemelen en iyi yoldur.

JS motoruna güvenmek aşağıdaki avantajları sunar:

  1. JSON spesifikasyonu değiştikçe daha kapsamlı ve sürekli güncel
  2. Daha hızlı çalışma olasılığı (daha düşük seviye kodu olduğu için)

JavaScript motoruna yaslanma fırsatı verildiğinde, bunu yapmanızı öneririm. Özellikle bu durumda. O olsa da hissetmek bir istisna yakalamak için hacky, gerçekten sadece harici yönteminden iki olası dönüş durumlarını hallediyoruz.


1

İşte Bourne'nin cevabında bazı küçük değişiklikler içeren bir kod. JSON.parse (sayı) herhangi bir istisnasız iyi çalışıyor, bu nedenle isNaN eklendi.

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

0

Tüm json dizeleri '{' veya '[' ile başlar ve karşılık gelen '}' veya ']' ile biter, bu yüzden bunu kontrol edin.

Angular.js bunu şöyle yapar:

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 netleştirmek için bakım? Bazen insanlar json'larına '[' ile başlarlar, ancak bu çok yaygın değildir.
carlin.scott

1
Geçerli JSON çalışmak için ayrıştırmak gerekir. Geçersiz JSON ise JSON değildir. Soru "bir dizenin JSON olup olmadığını nasıl anlarsınız?" Sorusudur. Yaklaşımınıza göre, bu JSON {fibble - olacaktır ve gerçekten JSON değildir. Kendi başına 1 numara gibi durumları da göz önünde bulundurun - bu geçerli JSON'dur.
Duke Dougal

1
Msgstr "Geçersiz JSON ise JSON değildir". "Geçerli" kelimesini kullanmanız gerektiği, sadece json'dan daha fazlası olduğu için bir nitelik eklediğinizi gösterir. Soru basitçe "bu json" idi ve kod örneğim ek soru kabul etmeden bu soruyu mükemmel cevaplar.
carlin.scott

bazı şablon sistemlerini kullanıyorsanız ve benzeri bir şey varsa kötü fikir { someValue }otomatik olarak geçer.
ncubica

@ ncubica, bu nedenle json dışında bir şey için şablon kullanıyorsunuz, dize yalnızca süslü parantez kullanan bir yer tutucu içeriyor ve şablon motoru, yer tutucuyu gerçek değerle değiştiremiyor mu? Ayrıca unutmayın, daha önce Duke'e açıkladığım gibi, asıl soru doğrulamadan bahsetmiyor. Sadece json gibi olup olmadığını bilmek istiyorlardı.
carlin.scott

0

Daktilo modunda öneriyorum :

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

0

Bunu kullandım (farklı cevapların bir karışımı, ama neyse):

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

Aşağıdakini deneyebilirsiniz, çünkü sayı, null, string'i de doğrular, ancak yukarıda işaretli cevap düzgün çalışmıyor, sadece yukarıdaki fonksiyonun bir düzeltmesi:

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

-1

Önceki yanıtlara ek olarak, "{}" gibi bir JSON biçimini doğrulamanız gerektiğinde aşağıdaki kodu kullanabilirsiniz:

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

Kullanım örnekleri:

validateJSON('{}')
true
validateJSON('[]')
false
validateJSON('')
false
validateJSON('2134')
false
validateJSON('{ "Id": 1, "Name": "Coke" }')
true
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.