मैं एक रेगेक्स की तलाश में हूं जो मुझे जोंस को मान्य करने की अनुमति देता है।
मैं रेगेक्स के लिए बहुत नया हूं और मुझे पर्याप्त पता है कि रेगेक्स के साथ पार्स करना बुरा है लेकिन क्या इसे मान्य करने के लिए इस्तेमाल किया जा सकता है?
मैं एक रेगेक्स की तलाश में हूं जो मुझे जोंस को मान्य करने की अनुमति देता है।
मैं रेगेक्स के लिए बहुत नया हूं और मुझे पर्याप्त पता है कि रेगेक्स के साथ पार्स करना बुरा है लेकिन क्या इसे मान्य करने के लिए इस्तेमाल किया जा सकता है?
जवाबों:
अधिकांश आधुनिक रेगेक्स कार्यान्वयन पुनरावर्ती सेंसरों के लिए अनुमति देते हैं, जो एक पूर्ण JSON क्रमिक संरचना को सत्यापित कर सकते हैं। Json.org विनिर्देश यह काफी सरल बना देता है।
$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
';
यह पीसीआरई कार्यों के साथ PHP में काफी अच्छी तरह से काम करता है । पर्ल में अनमॉडिफाइड काम करना चाहिए; और निश्चित रूप से अन्य भाषाओं के लिए अनुकूलित किया जा सकता है। इसके अलावा यह JSON परीक्षण मामलों के साथ सफल होता है ।
एक सरल दृष्टिकोण RFC4627, अनुभाग 6 में निर्दिष्ट न्यूनतम स्थिरता जांच है । हालांकि यह सिर्फ सुरक्षा परीक्षण और बुनियादी गैर-वैधता के रूप में इरादा है:
var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
text.replace(/"(\\.|[^"\\])*"/g, ''))) &&
eval('(' + text + ')');
falseमिलान जबकि शीर्ष स्तर JSON मान या तो एक सरणी या ऑब्जेक्ट होना चाहिए। इसमें स्ट्रिंग्स में या स्पेस में सेट किए गए कैरेक्टर सेट में भी कई मुद्दे हैं।
हां, यह एक सामान्य गलत धारणा है कि रेगुलर एक्सप्रेशंस केवल नियमित भाषाओं से मेल खा सकते हैं । वास्तव में, PCRE फ़ंक्शन नियमित भाषाओं की तुलना में बहुत अधिक मेल खा सकते हैं , वे कुछ गैर-संदर्भ-मुक्त भाषाओं से भी मेल खा सकते हैं! RegExps पर विकिपीडिया के लेख में इसके बारे में एक विशेष खंड है।
JSON को कई तरीकों से PCRE का उपयोग करके पहचाना जा सकता है! @ उमरियो ने सबपैटर्न और बैक-रेफरेंस नाम का एक बेहतरीन समाधान दिखाया । तब उन्होंने कहा कि पुनरावर्ती पैटर्न का उपयोग कर एक समाधान होना चाहिए (?R)। यहाँ इस तरह के regexp का एक उदाहरण 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';
मैं (?1)इसके बजाय उपयोग कर रहा हूं (?R)क्योंकि उत्तरार्द्ध पूरे पैटर्न को संदर्भित करता है , लेकिन हमारे पास \Aऔर \Zअनुक्रम हैं जो उपपट्टों के अंदर उपयोग नहीं किए जाने चाहिए। (?1)सबसे बाहरी कोष्ठकों द्वारा चिह्नित रेगेक्सपी के संदर्भ (यही कारण है कि सबसे बाहरी के ( )साथ शुरू नहीं होता है ?:)। तो, RegExp 268 अक्षर लंबा हो जाता है :)
/\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
वैसे भी, इसे एक "प्रौद्योगिकी प्रदर्शन" के रूप में माना जाना चाहिए, न कि व्यावहारिक समाधान के रूप में। PHP में मैं json_decode()फ़ंक्शन को कॉल करने के साथ JSON स्ट्रिंग को मान्य करूँगा (जैसे @Epcylon विख्यात)। अगर मैं उस JSON (यदि यह मान्य है) का उपयोग करने जा रहा हूं , तो यह सबसे अच्छा तरीका है।
\dखतरनाक है। कई regexp कार्यान्वयन \dमें एक अंक की यूनिकोड परिभाषा से मेल खाता है जो न केवल है [0-9]बल्कि इसके बजाय वैकल्पिक स्क्रिप्ट भी शामिल है।
\dहै कि पीसीआरई के PHP के कार्यान्वयन में यूनिकोड संख्याओं से मेल नहीं खाता है। उदाहरण के लिए ٩प्रतीक (0x669 अरबी-भारतीय अंकों नौ) पद्धति का उपयोग कर मिलान किया जाएगा #\p{Nd}#uलेकिन नहीं#\d#u
/uझंडे का इस्तेमाल नहीं किया । JSON को UTF-8 में एन्कोड किया गया है। एक उचित regexp के लिए आपको उस ध्वज का उपयोग करना चाहिए।
uसंशोधक का उपयोग किया था , कृपया मेरी पिछली टिप्पणी में पैटर्न पर फिर से देखें :) शीर्ष स्तर पर स्ट्रिंग्स, संख्याओं और बूलियनों का सही मिलान किया जाता है। आप यहाँ लंबे regexp को quanetic.com/Regex पेस्ट कर सकते हैं और अपने आप को आज़मा सकते हैं
JSON (नेस्टेड {...}-s) की पुनरावर्ती प्रकृति के कारण , रेगेक्स इसे मान्य करने के लिए अनुकूल नहीं है। ज़रूर, कुछ regex जायके पुनरावर्ती पैटर्न से मेल कर सकते हैं * (और उसके बाद JSON से मेल खा सकते हैं), लेकिन परिणामी पैटर्न देखने में भयानक हैं, और कभी भी उत्पादन कोड IMO में उपयोग नहीं किया जाना चाहिए!
* हालांकि खबरदार, कई रेगेक्स कार्यान्वयन पुनरावर्ती पैटर्न का समर्थन नहीं करते हैं। लोकप्रिय प्रोग्रामिंग भाषाओं में से, ये पुनरावर्ती पैटर्न का समर्थन करते हैं: पर्ल, .NET, पीएचपी और रूबी 1.9.2
मैंने @ mario के उत्तर की कोशिश की, लेकिन यह मेरे लिए काम नहीं किया, क्योंकि मैंने JSON.org ( संग्रह ) से टेस्ट सूट डाउनलोड किया है और इसमें 4 असफल परीक्षण थे (fail1.json, fail18.json, fail25.json, fail27। json)।
मैंने त्रुटियों की जांच की है और पाया है कि fail1.jsonवास्तव में सही है (मैनुअल के नोट के अनुसार और RFC-7159 वैध स्ट्रिंग भी एक वैध JSON है)। फ़ाइल fail18.jsonया तो मामला नहीं था, क्योंकि इसमें वास्तव में गहरी नेस्टेड JSON शामिल है:
[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
तो दो फाइलें बचीं: fail25.jsonऔर fail27.json:
[" tab character in string "]
तथा
["line
break"]
दोनों में अमान्य वर्ण हैं। इसलिए मैंने इस तरह के पैटर्न को अपडेट किया है (स्ट्रिंग सबपैटर्न अपडेट किया गया):
$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';
JSON के लिए दस्तावेज़ीकरण को देखते हुए , ऐसा लगता है कि रेगेक्स केवल तीन भागों में हो सकता है यदि लक्ष्य सिर्फ फिटनेस की जांच करना है:
[] या तो समाप्त होता है{}
[{\[]{1}...[}\]]{1}[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]... ...""
".*?"... ...सभी एक साथ:
[{\[]{1}([,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]|".*?")+[}\]]{1}
यदि JSON स्ट्रिंग में newlineवर्ण हैं, तो आपको singlelineअपने regex स्वाद पर स्विच का उपयोग करना चाहिए ताकि .मेल खाता हो newline। कृपया ध्यान दें कि यह सभी खराब JSON पर विफल नहीं होगा, लेकिन यह विफल हो जाएगा यदि मूल JSON संरचना अमान्य है, जो कि पार्सर को पास करने से पहले एक बुनियादी पवित्रता सत्यापन करने के लिए एक सीधा-आगे का रास्ता है।
मैंने मारियो के समाधान का एक रूबी कार्यान्वयन बनाया, जो काम करता है:
# 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
"स्ट्रिंग्स और संख्याओं" के लिए, मुझे लगता है कि संख्याओं के लिए आंशिक नियमित अभिव्यक्ति:
-?(?:0|[1-9]\d*)(?:\.\d+)(?:[eE][+-]\d+)?
इसके बजाय होना चाहिए:
-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?
चूँकि संख्या का दशमलव भाग वैकल्पिक है, और यह भी -प्रतीक से बचने के लिए संभवतः सुरक्षित है [+-]क्योंकि इसमें कोष्ठक के बीच एक विशेष अर्थ है।
\dखतरनाक है। कई regexp कार्यान्वयन \dमें एक अंक की यूनिकोड परिभाषा से मेल खाता है जो न केवल है [0-9]बल्कि इसके बजाय वैकल्पिक स्क्रिप्ट भी शामिल है।
एक JSON सरणी में एक अनुगामी अल्पविराम ने मेरे पर्ल 5.16 को लटका दिया, संभवतः इसलिए कि यह पीछे रह गया। मुझे एक बैक-टर्म-टर्मिनेटिंग निर्देश जोड़ना था:
(?<json> \s* (?: (?&number) | (?&boolean) | (?&string) | (?&array) | (?&object) )(*PRUNE) \s* )
^^^^^^^^
इस तरह, एक बार जब यह एक ऐसे निर्माण की पहचान कर लेता है जो 'वैकल्पिक' ( *या ?) नहीं है, तो इसे कुछ और के रूप में पहचानने की कोशिश करने के लिए इसे पीछे नहीं करना चाहिए।
जैसा कि ऊपर लिखा गया था, यदि आप जिस भाषा का उपयोग करते हैं, उसमें JSON-Library आती है, तो स्ट्रिंग को डिकोड करने की कोशिश करें और यदि वह विफल हो जाए तो अपवाद / त्रुटि को पकड़ लें! यदि भाषा नहीं है (बस ऐसे ही FreeMarker के साथ ऐसा मामला था) तो निम्न regex कम से कम कुछ बहुत ही मूल सत्यापन प्रदान कर सकता है (यह PHP / PCRE के लिए अधिक उपयोगकर्ताओं के लिए परीक्षण करने योग्य / उपयोगी होने के लिए लिखा गया है)। यह स्वीकार किए जाते हैं समाधान के रूप में मूर्ख नहीं है, लेकिन यह भी डरावना नहीं है)):
~^\{\s*\".*\}$|^\[\n?\{\s*\".*\}\n?\]$~s
संक्षिप्त विवरण:
// 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)
अगर मुझे कुछ याद आया, जो अनायास ही टूट जाएगा, तो मैं टिप्पणियों के लिए आभारी हूं!
यह कुंजी (स्ट्रिंग) को मान्य करता है: मान (स्ट्रिंग, पूर्णांक, [{कुंजी: मूल्य}, {कुंजी: मूल्य}], {कुंजी: मूल्य})
^\{(\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)*\}$
{
"key":"string",
"key": 56,
"key":{
"attr":"integer",
"attr": 12
},
"key":{
"key":[
{
"attr": 4,
"attr": "string"
}
]
}
}
यहाँ मेरा स्ट्रिंग स्ट्रिंग के लिए मान्य है:
^\"([^\"\\]*|\\(["\\\/bfnrt]{1}|u[a-f0-9]{4}))*\"$
Usign मूल वाक्यविन्यास आरेख लिखा गया था ।