Mengapa repot-repot dengan langkah validasi terpisah? Sebagian besar bahasa memiliki pustaka JSON yang dapat mengurai JSON, dan jika dapat menguraikannya, itu valid. Jika tidak, perpustakaan akan memberi tahu Anda.
Epcylon
Anda perlu mengurai teks untuk memvalidasinya ...
Ken
3
@ Mario - Saya tidak tahu ... Saya semua karena menyalahgunakan regex, dan sangat bersimpati terhadap keberatan Anda terhadap kekeliruan "regex harus cocok dengan reguler" - tetapi tidak pada pertanyaan praktis terkait pekerjaan. Jawaban terbaik di sini adalah benar-benar komentar Epcylon ... (mungkin diskusi ini termasuk dalam obrolan?)
Kobi
1
Kasus penggunaan praktis lainnya adalah menemukan ekspresi JSON dalam string yang lebih besar. Jika Anda hanya ingin bertanya "apakah string ini di sini adalah objek JSON", ya, pustaka penguraian JSON mungkin adalah alat yang lebih baik. Tetapi tidak dapat menemukan objek JSON dalam struktur yang lebih besar untuk Anda.
Sebagian besar implementasi regex modern memungkinkan ekspresi ekspresi rekursif, yang dapat memverifikasi struktur serial JSON lengkap. The spesifikasi json.org membuatnya cukup mudah.
Ia bekerja cukup baik di PHP dengan fungsi PCRE . Harus bekerja tanpa modifikasi di Perl; dan tentunya bisa diadaptasi untuk bahasa lain. Juga berhasil dengan kasus uji JSON .
Verifikasi RFC4627 yang lebih sederhana
Pendekatan yang lebih sederhana adalah pemeriksaan konsistensi minimal seperti yang ditentukan dalam RFC4627, bagian 6 . Namun ini hanya dimaksudkan sebagai uji keamanan dan tindakan pencegahan non-validitas dasar:
var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
text.replace(/"(\\.|[^"\\])*"/g, ''))) &&
eval('(' + text + ')');
+1 Ada begitu banyak hal buruk di dunia ini dari orang-orang yang tidak mendapatkan sintaks regex dan menyalahgunakannya sebagai alasan untuk membenci mereka :(
NikiC
8
@ Mario, tidak yakin apakah menurut Anda saya berada di departemen-penentang , tetapi saya tidak. Perhatikan bahwa pernyataan Anda "Sebagian besar implementasi ekspresi reguler modern memungkinkan ekspresi ekspresi rekursif" sangat bisa diperdebatkan. AFAIK, hanya Perl, PHP dan .NET yang memiliki kemampuan untuk mendefinisikan pola rekursif. Saya tidak akan menyebutnya "paling".
Bart Kiers
3
@Bart: Ya, itu memang bisa diperdebatkan. Ironisnya, mesin regex Javascript tidak dapat menggunakan regex rekursif seperti itu untuk memverifikasi JSON (atau hanya dengan solusi yang rumit). Jadi jika regex == posix regex, itu bukan pilihan. Namun menarik bahwa hal itu dapat dilakukan dengan implementasi kontemporer; bahkan dengan beberapa kasus penggunaan praktis. (Tapi benar, libpcre bukanlah mesin umum di mana-mana.) - Juga sebagai catatan: Saya berharap untuk lencana pembalikan sintetis, tetapi Anda tidak mendapatkan beberapa suara naik kereta musik menghalangi itu. : /
mario
4
Nggak. Saya mencari lencana Populis, yang memerlukan 20 suara tetapi masih 10 suara untuk jawaban Anda. Jadi sebaliknya, suara negatif pada pertanyaan Anda tidak menguntungkan saya untuk itu.
mario
2
Nah, melihat lebih jauh, regexp ini memiliki banyak masalah lainnya. Ini cocok dengan data JSON, tetapi beberapa data non-JSON juga cocok. Misalnya, literal tunggal falsecocok sedangkan nilai JSON tingkat atas harus berupa larik atau objek. Ini juga memiliki banyak masalah dalam kumpulan karakter yang diperbolehkan dalam string atau dalam spasi.
dolmen
32
Ya, ini adalah kesalahpahaman umum bahwa Ekspresi Reguler hanya dapat cocok dengan bahasa biasa . Faktanya, fungsi PCRE dapat mencocokkan lebih dari bahasa biasa , mereka dapat mencocokkan bahkan beberapa bahasa non-konteks-bebas! Artikel Wikipedia tentang RegExps memiliki bagian khusus tentangnya.
JSON dapat dikenali menggunakan PCRE dengan beberapa cara! @mario menunjukkan satu solusi hebat menggunakan subpattern dan referensi latar bernama . Kemudian dia mencatat bahwa harus ada solusi dengan menggunakan pola rekursif(?R) . Berikut adalah contoh regexp yang ditulis dalam PHP:
$regexString = '"([^"\\\\]*|\\\\["\\\\bfnrt\/]|\\\\u[0-9a-f]{4})*"';
$regexNumber = '-?(?=[1-9]|0(?!\d))\d+(\.\d+)?([eE][+-]?\d+)?';
$regexBoolean= 'true|false|null'; // these are actually copied from Mario's answer
$regex = '/\A('.$regexString.'|'.$regexNumber.'|'.$regexBoolean.'|'; //string, number, boolean
$regex.= '\[(?:(?1)(?:,(?1))*)?\s*\]|'; //arrays
$regex.= '\{(?:\s*'.$regexString.'\s*:(?1)(?:,\s*'.$regexString.'\s*:(?1))*)?\s*\}'; //objects
$regex.= ')\Z/is';
Saya menggunakan (?1)bukannya (?R)karena yang terakhir mereferensikan seluruh pola, tetapi kami memiliki \Adan \Zurutan yang tidak boleh digunakan di dalam subpattern.(?1)referensi ke regexp yang ditandai dengan tanda kurung terluar (inilah mengapa yang paling luar ( )tidak dimulai dengan ?:). Jadi, RegExp menjadi 268 karakter :)
Bagaimanapun, ini harus diperlakukan sebagai "demonstrasi teknologi", bukan sebagai solusi praktis. Di PHP saya akan memvalidasi string JSON dengan memanggil json_decode()fungsi (seperti yang dicatat @Epcylon). Jika saya akan menggunakan JSON itu (jika divalidasi), maka ini adalah metode terbaik.
Menggunakan \ditu berbahaya. Dalam banyak implementasi regexp \dcocok dengan definisi Unicode dari sebuah digit yang tidak hanya [0-9]berisi skrip alternatif.
dolmen
@dolmen: Anda mungkin benar, tetapi Anda tidak boleh mengeditnya sendiri menjadi pertanyaan. Cukup menambahkannya sebagai komentar sudah cukup.
Dennis Haarbrink
Saya pikir \dtidak cocok dengan nomor unicode dalam implementasi PHP PCRE. Misalnya ٩simbol (0x669 arabic-indic digit sembilan) akan dicocokkan menggunakan pola #\p{Nd}#utetapi tidak#\d#u
Hrant Khachatrian
@ hrant-khachatrian: ini bukan karena Anda tidak menggunakan /ubendera. JSON dikodekan dalam UTF-8. Untuk ekspresi reguler yang tepat, Anda harus menggunakan tanda itu.
dolmen
1
@dolmen Saya memang menggunakan upengubah, harap lihat kembali pola di komentar saya sebelumnya :) String, angka, dan boolean SUDAH cocok dengan benar di tingkat atas. Anda dapat menempelkan ekspresi reguler panjang di sini quanetic.com/Regex dan coba sendiri
Hrant Khachatrian
14
Karena sifat rekursif JSON (nested {...}-s), regex tidak cocok untuk memvalidasinya. Tentu, beberapa ragam ekspresi reguler dapat mencocokkan pola * secara rekursif (dan karenanya dapat mencocokkan JSON), tetapi pola yang dihasilkan sangat mengerikan untuk dilihat, dan tidak boleh digunakan dalam kode produksi IMO!
* Hati-hati, banyak implementasi regex tidak mendukung pola rekursif. Dari bahasa pemrograman populer, ini mendukung pola rekursif: Perl, .NET, PHP dan Ruby 1.9.2
@ semua pemilih ke bawah: "regex tidak cocok untuk memvalidasinya" tidak berarti mesin regex tertentu tidak dapat melakukannya (setidaknya, itulah yang saya maksud). Tentu, beberapa implementasi regex bisa , tapi siapa pun yang waras hanya akan menggunakan pengurai JSON. Sama seperti jika seseorang bertanya bagaimana membangun rumah lengkap hanya dengan palu, saya akan menjawab bahwa palu tidak cocok untuk pekerjaan itu, Anda memerlukan peralatan dan mesin yang lengkap. Memang, seseorang dengan ketahanan yang cukup dapat melakukannya hanya dengan palu.
Bart Kiers
1
Ini mungkin peringatan yang valid, tetapi tidak menjawab pertanyaan . Regex mungkin bukan alat yang tepat, tetapi beberapa orang tidak punya pilihan. Kami terkunci pada produk vendor yang mengevaluasi keluaran layanan untuk memeriksa kesehatannya, dan satu-satunya opsi yang disediakan vendor untuk pemeriksaan kesehatan khusus adalah formulir web yang menerima regex. Produk vendor yang mengevaluasi status layanan tidak berada di bawah kendali tim saya. Bagi kami, mengevaluasi JSON dengan regex sekarang menjadi persyaratan, oleh karena itu, jawaban "tidak cocok" tidak layak. (Saya masih tidak meremehkan Anda.)
John Deters
12
Saya mencoba jawaban @ mario, tetapi tidak berhasil untuk saya, karena saya telah mengunduh rangkaian pengujian dari JSON.org ( arsip ) dan ada 4 pengujian yang gagal (fail1.json, fail18.json, fail25.json, fail27. json).
Saya telah menyelidiki kesalahan dan menemukan, itu fail1.jsonsebenarnya benar (menurut catatan manual dan string valid RFC-7159 juga merupakan JSON yang valid). File fail18.jsonjuga bukan masalahnya, karena file berisi JSON bertingkat dalam yang benar:
Jika string JSON berisi newlinekarakter, Anda harus menggunakan singlelinesakelar pada ragam regex Anda agar .cocok newline. Harap dicatat bahwa ini tidak akan gagal pada semua JSON yang buruk, tetapi akan gagal jika struktur JSON dasar tidak valid, yang merupakan cara langsung untuk melakukan validasi kewarasan dasar sebelum meneruskannya ke parser.
Regex yang disarankan memiliki perilaku mundur yang mengerikan pada kasus pengujian tertentu. Jika Anda mencoba menjalankannya di '{"a": false, "b": true, "c": 100, "' json yang tidak lengkap ini, json akan berhenti. Contoh: regex101.com/r/Zzc6sz . Perbaikan sederhana adalah : [{[] {1} ([,: {} [] 0-9. \ - + Eaeflnr-u \ n \ r \ t] | ". *?") + [}]] {1}
Toonijn
@Toonijn Saya telah memperbarui untuk mencerminkan komentar Anda. Terima kasih!
cjbarth
3
Saya membuat implementasi Ruby dari solusi Mario, yang berfungsi:
# encoding: utf-8moduleConstantsJSON_VALIDATOR_RE = /(
# define subtypes and build up the json syntax, BNF-grammar-style
# The {0} is a hack to simply define them as named groups here but not match on them yet
# I added some atomic grouping to prevent catastrophic backtracking on invalid inputs
(?<number> -?(?=[1-9]|0(?!\d))\d+(\.\d+)?([eE][+-]?\d+)?){0}
(?<boolean> true | false | null ){0}
(?<string> " (?>[^"\\\\]* | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9a-f]{4} )* " ){0}
(?<array> \[ (?> \g<json> (?: , \g<json> )* )? \s* \] ){0}
(?<pair> \s* \g<string> \s* : \g<json> ){0}
(?<object> \{ (?> \g<pair> (?: , \g<pair> )* )? \s* \} ){0}
(?<json> \s* (?> \g<number> | \g<boolean> | \g<string> | \g<array> | \g<object> ) \s* ){0}
)
\A \g<json> \Z
/uix
end
########## inline test running
if __FILE__==$PROGRAM_NAME
# support
classString
def unindent
gsub(/^#{scan(/^(?!\n)\s*/).min_by{|l|l.length}}/u, "")
endend
require 'test/unit' unless defined? Test::UnitclassJsonValidationTest < Test::Unit::TestCaseincludeConstants
def setup
end
def test_json_validator_simple_string
assert_not_nil %s[ {"somedata": 5 }].match(JSON_VALIDATOR_RE)
end
def test_json_validator_deep_string
long_json = <<-JSON.unindent
{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"id": 1918723,
"boolean": true,
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}
JSON
assert_not_nil long_json.match(JSON_VALIDATOR_RE)
endendend
Menggunakan \ d berbahaya. Dalam banyak implementasi regexp \ d cocok dengan definisi Unicode dari sebuah digit yang tidak hanya [0-9] tetapi juga menyertakan skrip alternatif. Jadi, kecuali dukungan Unicode di Ruby masih rusak, Anda harus memperbaiki regexp di kode Anda.
dolmen
Sejauh yang saya tahu, Ruby menggunakan PCRE di mana \ d tidak cocok dengan SEMUA definisi unicode dari "digit." Atau apakah Anda mengatakan bahwa itu harus?
Tidak terlalu sulit untuk ditambahkan sebagai kasus uji dan kemudian mengubah kode agar lulus. Bagaimana membuatnya tidak meledakkan tumpukan dengan kedalaman 1000+ adalah masalah yang sama sekali berbeda, meskipun ...
pmarreck
1
Untuk "string dan angka", menurut saya ekspresi reguler parsial untuk angka:
-?(?:0|[1-9]\d*)(?:\.\d+)(?:[eE][+-]\d+)?
seharusnya sebagai gantinya:
-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?
karena bagian desimal dari angka tersebut adalah opsional, dan juga mungkin lebih aman untuk melepaskan -simbol [+-]karena memiliki arti khusus di antara tanda kurung
Menggunakan \ditu berbahaya. Dalam banyak implementasi regexp \dcocok dengan definisi Unicode dari sebuah digit yang tidak hanya [0-9]berisi skrip alternatif.
dolmen
Kelihatannya agak aneh, bahwa -0 adalah angka yang valid tetapi RFC 4627 mengizinkannya dan ekspresi reguler Anda sesuai dengannya.
ceving
1
Tanda koma dalam larik JSON menyebabkan Perl 5.16 saya hang, mungkin karena terus mundur. Saya harus menambahkan arahan penghentian mundur:
Dengan cara ini, setelah mengidentifikasi konstruksi yang bukan 'opsional' ( *atau ?), ia tidak boleh mencoba mundur untuk mencoba mengidentifikasinya sebagai sesuatu yang lain.
Seperti yang ditulis di atas, jika bahasa yang Anda gunakan memiliki perpustakaan JSON yang menyertainya, gunakan untuk mencoba mendekode string dan menangkap pengecualian / kesalahan jika gagal! Jika bahasanya tidak (hanya memiliki kasus seperti itu dengan FreeMarker), regex berikut setidaknya dapat memberikan beberapa validasi yang sangat dasar (itu ditulis untuk PHP / PCRE agar dapat diuji / digunakan untuk lebih banyak pengguna). Ini tidak semudah solusi yang diterima, tetapi juga tidak terlalu menakutkan =):
~^\{\s*\".*\}$|^\[\n?\{\s*\".*\}\n?\]$~s
penjelasan singkat:
// we have two possibilities in case the string is JSON// 1. the string passed is "just" a JSON object, e.g. {"item": [], "anotheritem": "content"}// this can be matched by the following regex which makes sure there is at least a {" at the// beginning of the string and a } at the end of the string, whatever is inbetween is not checked!
^\{\s*\".*\}$
// OR (character "|" in the regex pattern)// 2. the string passed is a JSON array, e.g. [{"item": "value"}, {"item": "value"}]// which would be matched by the second part of the pattern above
^\[\n?\{\s*\".*\}\n?\]$
// the s modifier is used to make "." also match newline characters (can happen in prettyfied JSON)
jika saya melewatkan sesuatu yang akan merusak ini secara tidak sengaja, saya berterima kasih atas komentar!
Saya menyadari bahwa ini lebih dari 6 tahun yang lalu. Namun, saya pikir ada solusi yang tidak disebutkan oleh siapa pun di sini yang jauh lebih mudah daripada regexing
Jawaban:
Ya, validasi regex lengkap dimungkinkan.
Sebagian besar implementasi regex modern memungkinkan ekspresi ekspresi rekursif, yang dapat memverifikasi struktur serial JSON lengkap. The spesifikasi json.org membuatnya cukup mudah.
$pcre_regex = ' / (?(DEFINE) (?<number> -? (?= [1-9]|0(?!\d) ) \d+ (\.\d+)? ([eE] [+-]? \d+)? ) (?<boolean> true | false | null ) (?<string> " ([^"\\\\]* | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9a-f]{4} )* " ) (?<array> \[ (?: (?&json) (?: , (?&json) )* )? \s* \] ) (?<pair> \s* (?&string) \s* : (?&json) ) (?<object> \{ (?: (?&pair) (?: , (?&pair) )* )? \s* \} ) (?<json> \s* (?: (?&number) | (?&boolean) | (?&string) | (?&array) | (?&object) ) \s* ) ) \A (?&json) \Z /six ';
Ia bekerja cukup baik di PHP dengan fungsi PCRE . Harus bekerja tanpa modifikasi di Perl; dan tentunya bisa diadaptasi untuk bahasa lain. Juga berhasil dengan kasus uji JSON .
Verifikasi RFC4627 yang lebih sederhana
Pendekatan yang lebih sederhana adalah pemeriksaan konsistensi minimal seperti yang ditentukan dalam RFC4627, bagian 6 . Namun ini hanya dimaksudkan sebagai uji keamanan dan tindakan pencegahan non-validitas dasar:
var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test( text.replace(/"(\\.|[^"\\])*"/g, ''))) && eval('(' + text + ')');
sumber
false
cocok sedangkan nilai JSON tingkat atas harus berupa larik atau objek. Ini juga memiliki banyak masalah dalam kumpulan karakter yang diperbolehkan dalam string atau dalam spasi.Ya, ini adalah kesalahpahaman umum bahwa Ekspresi Reguler hanya dapat cocok dengan bahasa biasa . Faktanya, fungsi PCRE dapat mencocokkan lebih dari bahasa biasa , mereka dapat mencocokkan bahkan beberapa bahasa non-konteks-bebas! Artikel Wikipedia tentang RegExps memiliki bagian khusus tentangnya.
JSON dapat dikenali menggunakan PCRE dengan beberapa cara! @mario menunjukkan satu solusi hebat menggunakan subpattern dan referensi latar bernama . Kemudian dia mencatat bahwa harus ada solusi dengan menggunakan pola rekursif
(?R)
. Berikut adalah contoh regexp yang ditulis dalam PHP:$regexString = '"([^"\\\\]*|\\\\["\\\\bfnrt\/]|\\\\u[0-9a-f]{4})*"'; $regexNumber = '-?(?=[1-9]|0(?!\d))\d+(\.\d+)?([eE][+-]?\d+)?'; $regexBoolean= 'true|false|null'; // these are actually copied from Mario's answer $regex = '/\A('.$regexString.'|'.$regexNumber.'|'.$regexBoolean.'|'; //string, number, boolean $regex.= '\[(?:(?1)(?:,(?1))*)?\s*\]|'; //arrays $regex.= '\{(?:\s*'.$regexString.'\s*:(?1)(?:,\s*'.$regexString.'\s*:(?1))*)?\s*\}'; //objects $regex.= ')\Z/is';
Saya menggunakan
(?1)
bukannya(?R)
karena yang terakhir mereferensikan seluruh pola, tetapi kami memiliki\A
dan\Z
urutan yang tidak boleh digunakan di dalam subpattern.(?1)
referensi ke regexp yang ditandai dengan tanda kurung terluar (inilah mengapa yang paling luar( )
tidak dimulai dengan?:
). Jadi, RegExp menjadi 268 karakter :)/\A("([^"\\]*|\\["\\bfnrt\/]|\\u[0-9a-f]{4})*"|-?(?=[1-9]|0(?!\d))\d+(\.\d+)?([eE][+-]?\d+)?|true|false|null|\[(?:(?1)(?:,(?1))*)?\s*\]|\{(?:\s*"([^"\\]*|\\["\\bfnrt\/]|\\u[0-9a-f]{4})*"\s*:(?1)(?:,\s*"([^"\\]*|\\["\\bfnrt\/]|\\u[0-9a-f]{4})*"\s*:(?1))*)?\s*\})\Z/is
Bagaimanapun, ini harus diperlakukan sebagai "demonstrasi teknologi", bukan sebagai solusi praktis. Di PHP saya akan memvalidasi string JSON dengan memanggil
json_decode()
fungsi (seperti yang dicatat @Epcylon). Jika saya akan menggunakan JSON itu (jika divalidasi), maka ini adalah metode terbaik.sumber
\d
itu berbahaya. Dalam banyak implementasi regexp\d
cocok dengan definisi Unicode dari sebuah digit yang tidak hanya[0-9]
berisi skrip alternatif.\d
tidak cocok dengan nomor unicode dalam implementasi PHP PCRE. Misalnya٩
simbol (0x669 arabic-indic digit sembilan) akan dicocokkan menggunakan pola#\p{Nd}#u
tetapi tidak#\d#u
/u
bendera. JSON dikodekan dalam UTF-8. Untuk ekspresi reguler yang tepat, Anda harus menggunakan tanda itu.u
pengubah, harap lihat kembali pola di komentar saya sebelumnya :) String, angka, dan boolean SUDAH cocok dengan benar di tingkat atas. Anda dapat menempelkan ekspresi reguler panjang di sini quanetic.com/Regex dan coba sendiriKarena sifat rekursif JSON (nested
{...}
-s), regex tidak cocok untuk memvalidasinya. Tentu, beberapa ragam ekspresi reguler dapat mencocokkan pola * secara rekursif (dan karenanya dapat mencocokkan JSON), tetapi pola yang dihasilkan sangat mengerikan untuk dilihat, dan tidak boleh digunakan dalam kode produksi IMO!* Hati-hati, banyak implementasi regex tidak mendukung pola rekursif. Dari bahasa pemrograman populer, ini mendukung pola rekursif: Perl, .NET, PHP dan Ruby 1.9.2
sumber
Saya mencoba jawaban @ mario, tetapi tidak berhasil untuk saya, karena saya telah mengunduh rangkaian pengujian dari JSON.org ( arsip ) dan ada 4 pengujian yang gagal (fail1.json, fail18.json, fail25.json, fail27. json).
Saya telah menyelidiki kesalahan dan menemukan, itu
fail1.json
sebenarnya benar (menurut catatan manual dan string valid RFC-7159 juga merupakan JSON yang valid). Filefail18.json
juga bukan masalahnya, karena file berisi JSON bertingkat dalam yang benar:[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
Jadi dua file tersisa:
fail25.json
danfail27.json
:[" tab character in string "]
dan
["line break"]
Keduanya mengandung karakter yang tidak valid. Jadi saya telah memperbarui pola seperti ini (string subpattern diperbarui):
$pcreRegex = '/ (?(DEFINE) (?<number> -? (?= [1-9]|0(?!\d) ) \d+ (\.\d+)? ([eE] [+-]? \d+)? ) (?<boolean> true | false | null ) (?<string> " ([^"\n\r\t\\\\]* | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9a-f]{4} )* " ) (?<array> \[ (?: (?&json) (?: , (?&json) )* )? \s* \] ) (?<pair> \s* (?&string) \s* : (?&json) ) (?<object> \{ (?: (?&pair) (?: , (?&pair) )* )? \s* \} ) (?<json> \s* (?: (?&number) | (?&boolean) | (?&string) | (?&array) | (?&object) ) \s* ) ) \A (?&json) \Z /six';
Jadi sekarang semua tes hukum dari json.org dapat dilalui.
sumber
Melihat dokumentasi untuk JSON , tampaknya regex dapat menjadi tiga bagian jika tujuannya hanya untuk memeriksa kesesuaian:
[]
atau{}
[{\[]{1}
...[}\]]{1}
[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]
...""
".*?"
...Bersama:
[{\[]{1}([,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]|".*?")+[}\]]{1}
Jika string JSON berisi
newline
karakter, Anda harus menggunakansingleline
sakelar pada ragam regex Anda agar.
cocoknewline
. Harap dicatat bahwa ini tidak akan gagal pada semua JSON yang buruk, tetapi akan gagal jika struktur JSON dasar tidak valid, yang merupakan cara langsung untuk melakukan validasi kewarasan dasar sebelum meneruskannya ke parser.sumber
Saya membuat implementasi Ruby dari solusi Mario, yang berfungsi:
# encoding: utf-8 module Constants JSON_VALIDATOR_RE = /( # define subtypes and build up the json syntax, BNF-grammar-style # The {0} is a hack to simply define them as named groups here but not match on them yet # I added some atomic grouping to prevent catastrophic backtracking on invalid inputs (?<number> -?(?=[1-9]|0(?!\d))\d+(\.\d+)?([eE][+-]?\d+)?){0} (?<boolean> true | false | null ){0} (?<string> " (?>[^"\\\\]* | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9a-f]{4} )* " ){0} (?<array> \[ (?> \g<json> (?: , \g<json> )* )? \s* \] ){0} (?<pair> \s* \g<string> \s* : \g<json> ){0} (?<object> \{ (?> \g<pair> (?: , \g<pair> )* )? \s* \} ){0} (?<json> \s* (?> \g<number> | \g<boolean> | \g<string> | \g<array> | \g<object> ) \s* ){0} ) \A \g<json> \Z /uix end ########## inline test running if __FILE__==$PROGRAM_NAME # support class String def unindent gsub(/^#{scan(/^(?!\n)\s*/).min_by{|l|l.length}}/u, "") end end require 'test/unit' unless defined? Test::Unit class JsonValidationTest < Test::Unit::TestCase include Constants def setup end def test_json_validator_simple_string assert_not_nil %s[ {"somedata": 5 }].match(JSON_VALIDATOR_RE) end def test_json_validator_deep_string long_json = <<-JSON.unindent { "glossary": { "title": "example glossary", "GlossDiv": { "id": 1918723, "boolean": true, "title": "S", "GlossList": { "GlossEntry": { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": { "para": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": ["GML", "XML"] }, "GlossSee": "markup" } } } } } JSON assert_not_nil long_json.match(JSON_VALIDATOR_RE) end end end
sumber
Untuk "string dan angka", menurut saya ekspresi reguler parsial untuk angka:
-?(?:0|[1-9]\d*)(?:\.\d+)(?:[eE][+-]\d+)?
seharusnya sebagai gantinya:
-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?
karena bagian desimal dari angka tersebut adalah opsional, dan juga mungkin lebih aman untuk melepaskan
-
simbol[+-]
karena memiliki arti khusus di antara tanda kurungsumber
\d
itu berbahaya. Dalam banyak implementasi regexp\d
cocok dengan definisi Unicode dari sebuah digit yang tidak hanya[0-9]
berisi skrip alternatif.Tanda koma dalam larik JSON menyebabkan Perl 5.16 saya hang, mungkin karena terus mundur. Saya harus menambahkan arahan penghentian mundur:
(?<json> \s* (?: (?&number) | (?&boolean) | (?&string) | (?&array) | (?&object) )(*PRUNE) \s* ) ^^^^^^^^
Dengan cara ini, setelah mengidentifikasi konstruksi yang bukan 'opsional' (
*
atau?
), ia tidak boleh mencoba mundur untuk mencoba mengidentifikasinya sebagai sesuatu yang lain.sumber
Seperti yang ditulis di atas, jika bahasa yang Anda gunakan memiliki perpustakaan JSON yang menyertainya, gunakan untuk mencoba mendekode string dan menangkap pengecualian / kesalahan jika gagal! Jika bahasanya tidak (hanya memiliki kasus seperti itu dengan FreeMarker), regex berikut setidaknya dapat memberikan beberapa validasi yang sangat dasar (itu ditulis untuk PHP / PCRE agar dapat diuji / digunakan untuk lebih banyak pengguna). Ini tidak semudah solusi yang diterima, tetapi juga tidak terlalu menakutkan =):
~^\{\s*\".*\}$|^\[\n?\{\s*\".*\}\n?\]$~s
penjelasan singkat:
// we have two possibilities in case the string is JSON // 1. the string passed is "just" a JSON object, e.g. {"item": [], "anotheritem": "content"} // this can be matched by the following regex which makes sure there is at least a {" at the // beginning of the string and a } at the end of the string, whatever is inbetween is not checked! ^\{\s*\".*\}$ // OR (character "|" in the regex pattern) // 2. the string passed is a JSON array, e.g. [{"item": "value"}, {"item": "value"}] // which would be matched by the second part of the pattern above ^\[\n?\{\s*\".*\}\n?\]$ // the s modifier is used to make "." also match newline characters (can happen in prettyfied JSON)
jika saya melewatkan sesuatu yang akan merusak ini secara tidak sengaja, saya berterima kasih atas komentar!
sumber
Regex yang memvalidasi JSON sederhana, bukan JSONArray
itu memvalidasi kunci (string): nilai (string, integer, [{key: value}, {key: value}], {key: value})
^\{(\s|\n\s)*(("\w*"):(\s)*("\w*"|\d*|(\{(\s|\n\s)*(("\w*"):(\s)*("\w*(,\w+)*"|\d{1,}|\[(\s|\n\s)*(\{(\s|\n\s)*(("\w*"):(\s)*(("\w*"|\d{1,}))((,(\s|\n\s)*"\w*"):(\s)*("\w*"|\d{1,}))*(\s|\n)*\})){1}(\s|\n\s)*(,(\s|\n\s)*\{(\s|\n\s)*(("\w*"):(\s)*(("\w*"|\d{1,}))((,(\s|\n\s)*"\w*"):(\s)*("\w*"|\d{1,}))*(\s|\n)*\})?)*(\s|\n\s)*\]))((,(\s|\n\s)*"\w*"):(\s)*("\w*(,\w+)*"|\d{1,}|\[(\s|\n\s)*(\{(\s|\n\s)*(("\w*"):(\s)*(("\w*"|\d{1,}))((,(\s|\n\s)*"\w*"):(\s)*("\w*"|\d{1,}))*(\s|\n)*\})){1}(\s|\n\s)*(,(\s|\n\s)*\{(\s|\n\s)*(("\w*"):(\s)*(("\w*"|\d{1,}))((,(\s|\n\s)*"\w*"):("\w*"|\d{1,}))*(\s|\n)*\})?)*(\s|\n\s)*\]))*(\s|\n\s)*\}){1}))((,(\s|\n\s)*"\w*"):(\s)*("\w*"|\d*|(\{(\s|\n\s)*(("\w*"):(\s)*("\w*(,\w+)*"|\d{1,}|\[(\s|\n\s)*(\{(\s|\n\s)*(("\w*"):(\s)*(("\w*"|\d{1,}))((,(\s|\n\s)*"\w*"):(\s)*("\w*"|\d{1,}))*(\s|\n)*\})){1}(\s|\n\s)*(,(\s|\n\s)*\{(\s|\n\s)*(("\w*"):(\s)*(("\w*"|\d{1,}))((,(\s|\n\s)*"\w*"):(\s)*("\w*"|\d{1,}))*(\s|\n)*\})?)*(\s|\n\s)*\]))((,(\s|\n\s)*"\w*"):(\s)*("\w*(,\w+)*"|\d{1,}|\[(\s|\n\s)*(\{(\s|\n\s)*(("\w*"):(\s)*(("\w*"|\d{1,}))((,(\s|\n\s)*"\w*"):(\s)*("\w*"|\d{1,}))*(\s|\n)*\})){1}(\s|\n\s)*(,(\s|\n\s)*\{(\s|\n\s)*(("\w*"):(\s)*(("\w*"|\d{1,}))((,(\s|\n\s)*"\w*"):("\w*"|\d{1,}))*(\s|\n)*\})?)*(\s|\n\s)*\]))*(\s|\n\s)*\}){1}))*(\s|\n)*\}$
contoh data yang divalidasi oleh JSON ini
{ "key":"string", "key": 56, "key":{ "attr":"integer", "attr": 12 }, "key":{ "key":[ { "attr": 4, "attr": "string" } ] } }
sumber
Di sini regexp saya untuk memvalidasi string:
^\"([^\"\\]*|\\(["\\\/bfnrt]{1}|u[a-f0-9]{4}))*\"$
Ditulis menggunakan diagram sintaks asli .
sumber
Saya menyadari bahwa ini lebih dari 6 tahun yang lalu. Namun, saya pikir ada solusi yang tidak disebutkan oleh siapa pun di sini yang jauh lebih mudah daripada regexing
function isAJSON(string) { try { JSON.parse(string) } catch(e) { if(e instanceof SyntaxError) return false; }; return true; }
sumber