正则表达式验证JSON

Sha*_*ard 81 regex json

我正在寻找一个允许我验证json的正则表达式.

我是Regex的新手,我知道用Regex解析很糟糕,但可以用来验证吗?

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验证

一种更简单的方法是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)

  • +1世界上有太多不好的人,他们只是没有得到正则表达式的语法并且滥用那些作为讨厌它们的理由:( (20认同)
  • @mario,不确定你是否认为我在_the-naysayers-department_,但我不是.请注意,您的语句_"大多数现代正则表达式实现允许递归regexpressions"_是值得商榷的.AFAIK,只有Perl,PHP和.NET才能定义递归模式.我不会称之为"最". (6认同)
  • 不.我是在使用民粹主义徽章之后,我需要20票,但你的答案仍然是10票.所以恰恰相反,你问题上的贬值对我没有好处. (4认同)
  • @Bart:是的,这是值得商榷的.最具讽刺意味的是,Javascript正则表达式引擎无法使用这样的递归正则表达式来验证JSON(或者仅使用精心设计的变通方法).所以如果正则表达式== posix正则表达式,它不是一个选项.尽管如此,它仍然很有趣,它可以用于当代实现; 即使是很少的实际用例.(但事实上,libpcre并不是到处都是流行的引擎.) - 也是为了记录:我希望有一个合成的反转徽章,但你没有得到一些潮流的支持就会阻碍它.:/ (3认同)
  • 嗯,进一步看,这个正则表达式有许多其他问题.它匹配JSON数据,但也有一些非JSON数据匹配.例如,单个文字"false"匹配,而顶级JSON值必须是数组或对象.它在字符串或空格中允许的字符集中也存在许多问题. (2认同)
  • @Gajus:它失败了,因为你复制了 `\\\\ u [0-9a-f]+` 中的文字 4 个反斜杠。对于仅正则表达式的上下文,它只是 2 个反斜杠。 (2认同)

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(如果它已经过验证),那么这是最好的方法.

  • 我认为像这样的代码是非编码器关闭的原因! (3认同)

Bar*_*ers 13

由于JSON(嵌套{...}-s)的递归特性,正则表达式不适合验证它.当然,一些正则表达式可以递归地匹配模式*(并且因此可以匹配JSON),但是结果模式看起来很糟糕,并且永远不应该用于生产代码IMO!

*请注意,许多正则表达式实现支持递归模式.在流行的编程语言中,这些语言支持递归模式:Perl,.NET,PHP和Ruby 1.9.2

  • @all down选民:_"正则表达式不适合验证它"_并不意味着某些正则表达式引擎不能这样做(至少,这就是我的意思).当然,一些正则表达式实现_can_,但正确思维的任何人都只会使用JSON解析器.就像有人问如何用锤子建造一个完整的房子一样,我会回答说锤子不适合工作,你需要一套完整的工具包和机器.当然,有足够耐力的人可以用锤子做到这一点. (14认同)
  • 这可能是一个有效的警告,但它_不回答问题_。正则表达式可能不是正确的工具,但有些人别无选择。我们被锁定在评估服务输出以检查其健康状况的供应商产品中,供应商为自定义健康状况检查提供的唯一选项是接受正则表达式的 Web 表单。评估服务状态的供应商产品不在我的团队控制之下。对我们来说,使用正则表达式评估 JSON 现在是一项要求,因此,“不合适”的答案是不可行的。(我仍然没有贬低你。) (3认同)
  • [幽默相关的相关问题](http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags)... (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.jsonfail27.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的所有法律测试.


cjb*_*rth 6

查看JSON的文档,如果目标只是检查适合度,则正则表达式似乎可以简单地分为三个部分:

  1. 字符串以或开始结束[]{}
    • [{\[]{1}...[}\]]{1}
    1. 该字符是允许的 JSON 控制字符(仅一个)
      • ... [,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]...
    2. 包含在 a 中的字符集""
      • ... ".*?"...

全部一起: [{\[]{1}([,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]|".*?")+[}\]]{1}

如果 JSON 字符串包含newline字符,那么您应该使用singleline正则表达式风格的开关,以便.匹配newline. 请注意,这不会在所有错误的 JSON 上失败,但如果基本 JSON 结构无效,它将失败,这是在将其传递给解析器之前进行基本健全性验证的直接方法。

  • 建议的正则表达式在某些测试用例上具有可怕的回溯行为。如果您尝试在 '{"a":false, "b":true,"c":100,"' 这个不完整的 json 上运行它,它会停止。例如:https://regex101.com/r/Zzc6sz。A简单的解决方法是: [{\[]{1}([,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]|".*?")+[} \]]{1} (2认同)
  • @cjbarth 的这个稍微修改的版本非常适合我在文本中查找所有类似 JSON 的结构的用例(在我的例子中全局应用于 HTML 文件): `[{\[]{1}([,:{}\[ \]0-9.\-+A-zr-u \n\r\t]|".*:?")+[}\]]{1}` (2认同)