mar*_*rio 172
大多数现代正则表达式实现允许递归regexpressions,它可以验证完整的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
';
Run Code Online (Sandbox Code Playgroud)
它在PHP中与PCRE功能相当不错.应该在Perl中不做修改; 并且当然可以适应其他语言.它也可以成功使用JSON测试用例.
一种更简单的方法是RFC4627第6节中规定的最小一致性检查.然而,它只是作为安全测试和基本的非有效性预防措施:
var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
text.replace(/"(\\.|[^"\\])*"/g, ''))) &&
eval('(' + text + ')');
Run Code Online (Sandbox Code Playgroud)
Hra*_*ian 28
是的,正则表达式只能匹配常规语言,这是一种常见的误解.事实上,PCRE功能可以比常规语言更匹配,甚至可以匹配一些非上下文语言!维基百科关于RegExps的文章有一个特殊的部分.
可以通过多种方式使用PCRE识别JSON!@mario使用命名子模式和反向引用显示了一个很好的解决方案.然后他指出应该有一个使用递归模式 的解决方案(?R).以下是用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';
Run Code Online (Sandbox Code Playgroud)
我使用(?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
Run Code Online (Sandbox Code Playgroud)
无论如何,这应该被视为"技术演示",而不是一个实际的解决方案.在PHP中,我将通过调用json_decode()函数来验证JSON字符串(就像@Epcylon所说的那样).如果我要使用那个JSON(如果它已经过验证),那么这是最好的方法.
Bar*_*ers 13
由于JSON(嵌套{...}-s)的递归特性,正则表达式不适合验证它.当然,一些正则表达式可以递归地匹配模式*(并且因此可以匹配JSON),但是结果模式看起来很糟糕,并且永远不应该用于生产代码IMO!
*请注意,许多正则表达式实现不支持递归模式.在流行的编程语言中,这些语言支持递归模式:Perl,.NET,PHP和Ruby 1.9.2
Gin*_*ane 10
我尝试了@ mario的答案,但它对我不起作用,因为我从JSON.org(存档)下载了测试套件,并且有4个失败的测试(fail1.json,fail18.json,fail25.json,fail27. JSON).
我已经调查了错误并发现了,这fail1.json实际上是正确的(根据手册的说明和RFC-7159有效字符串也是一个有效的JSON).文件fail18.json也不是这样,因为它包含实际上正确的深层嵌套JSON:
[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
Run Code Online (Sandbox Code Playgroud)
所以剩下两个文件:fail25.json和fail27.json:
[" tab character in string "]
Run Code Online (Sandbox Code Playgroud)
和
["line
break"]
Run Code Online (Sandbox Code Playgroud)
两者都包含无效字符.所以我更新了这样的模式(字符串子模式更新):
$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';
Run Code Online (Sandbox Code Playgroud)
所以现在可以通过json.org的所有法律测试.
查看JSON的文档,如果目标只是检查适合度,则正则表达式似乎可以简单地分为三个部分:
[]{}
[{\[]{1}...[}\]]{1}[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]...""
".*?"...全部一起:
[{\[]{1}([,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]|".*?")+[}\]]{1}
如果 JSON 字符串包含newline字符,那么您应该使用singleline正则表达式风格的开关,以便.匹配newline. 请注意,这不会在所有错误的 JSON 上失败,但如果基本 JSON 结构无效,它将失败,这是在将其传递给解析器之前进行基本健全性验证的直接方法。