编写JSON验证器


12

编写一个确定其输入是否为有效JSON的程序

  • 输入: ASCII文本:[\x00-\x7F]*

    注意:如果ASCII有问题,请随时使用其他编码,但请在帖子中注明。

  • 输出: ValidInvalid。尾随换行符可以省略。

  • 例:

    $ echo '{"key": "value"}' | ./json-validate
    Valid
    $ echo '{key: "value"}' | ./json-validate
    Invalid
    
  • 规则:

    • 不要使用JSON解析库。
    • 允许使用部分正确的解决方案,但对此不以为然。
    • 发布您的测试套件分数(见下文)。

最短的正确的解决方案获胜。

请在您的程序上运行json-validate-test-suite.sh,然后发布分数。例:

$ ./json-validate-test-suite.sh ./buggy-prog
fail: should be invalid:  [ 0.1e ] 
fail: should be invalid:  [ 0.1e+-1 ] 
fail: should be invalid:  [ 0.1e-+1 ] 
score: 297/300

资源:


JSON语法如下:

json: object | array

object: '{' members? '}'
    members: pair (',' pair)*
    pair:    string ':' value

array: '[' elements? ']'
    elements: value (',' value)*

value: string
     | number
     | object
     | array
     | 'true'
     | 'false'
     | 'null'

string: '"' char* '"'
    char: [^"\\\x00-\x1F]
        | '\' escape
    escape: ["\\/bfnrt]
          | u [0-9A-Fa-f]{4}

number: '-'? (0 | [1-9][0-9]*) ('.' [0-9]+)? ([Ee] [+-]? [0-9]+)?

另外,空格可以出现在六个结构字符中的任何一个之前或之后 {}[]:,

ws = [\t\n\r ]*

请记住以下几点:

  • 请谨慎使用isspace()。JSON中的空白为[\t\n\r ],但isspace()也将\v(“垂直”标签)和\f(“换页”)视为空格。尽管单词拥有的不仅isdigit()可以接受[0-9],但在这里应该可以使用,因为我们假设输入是ASCII。
  • \x7F从技术上讲,它是一个控制字符,但JSON RFC并未提及(仅提及[\x00-\x1F]),并且大多数JSON解析器都倾向于接受\x7F字符串中的字符。由于存在这种歧义,解决方案可能选择接受还是不接受。

7
您的“允许部分正确的解决方案”说明使我梦想从遗传算法中提取正则表达式。我一定疯了
JB

@JB:太棒了。
乔伊·亚当斯

只是好奇,为什么要{key: "value"}考虑使用无效的JSON?这是有效的javascript。
2011年

@HoLyVieR:我想这样可以更轻松地解析JSON,并减少实现者的歧义。我不确定我是否也喜欢此限制。
乔伊·亚当斯

有人得到了验证脚本的副本吗?
Armand 2012年

Answers:


7

PHP:297 285 264 253个字符

<?=preg_match(<<<'R'
~([\h
]*)({(?1)((("([^"\\\0- ]| |\\(["\\/bfnrt]|u[\dA-Fa-f]{4}))*")(?1):(?1)((?5)|-?(0|[1-9]\d*)(\.\d+)?([Ee][+-]?\d+)?|(?2)|true|false|null))(((?1),(?1))(?4))*)?}|\[(?1)((?8)((?13)(?8))*)?(?1)])(?1)\z~A
R
,`cat`)?'Valid':'Invalid';

得分:300/300

这是JSON语法的完整,递归实现。

由于nowdoc语法,它仅在PHP≥5.3上有效(heredoc要求将all翻倍\)。

可读版本:

(这是相同的正则表达式,具有命名的捕获组和扩展的语法):

#!/usr/bin/env php
<?php

$re = <<< 'RE'
~\A (?P<ws>[\t\n\r ])* (
    (?P<object>\{ (?P>ws)*
        (?P<members>
            (?P<pair>
                (?P<string>
                    "(?P<char>
                        [^"\\\x00-\x1F]
                        |\\(?P<escape>
                            ["\\/bfnrt]
                            |u [0-9A-Fa-f]{4}
                        )
                    )*"
                ) (?P>ws)* : (?P>ws)* (?P<value>
                    (?P>string)
                    | (?P<number>-? (0 | [1-9][0-9]*) (\. [0-9]+)? ([Ee] [+-]? [0-9]+)? )
                    | (?P>object)
                    | (?P>array)
                    | true
                    | false
                    | null
                )
            ) ( (?P>ws)* , (?P>ws)* (?P>pair) )*
        )?
    \})
    |(?P<array>\[ (?P>ws)*
        (?P<elements>
            (?P>value) ( (?P>ws)* , (?P>ws)* (?P>value) )*
        )?
    (?P>ws)* \])
) (?P>ws)* \z~x
RE;

if (preg_match($re, stream_get_contents(STDIN))) {
    echo 'Valid';
} else {
    echo 'Invalid';
}

哇。`````
Nathan Osman

您需要包括<?phpIMO。
匿名

添加。现在有264个字符:-)
Arnaud Le Blanc

5

蟒蛇- 340 314 299 292个字符

import re,os
r=x=re.sub
z=r('0\.0+','0',r('e[+-]?0+|[\t\n\r]',' ',r(r'"(\\["nrtb\\/]|[^\\"\0-\37])*"','1',r(r'true|false|null|\\u\w{4}|[1-9]\d*','0',os.read(0,99)))))
while z!=x:z,x=r('\{(1:\d)?(,\\1)*\}|\[(-?\d(,-?\d)*)?\]','0',r(' *([][{}:,]) *','\\1',z)),z
print['Inv','V'][z=='0']+'alid'

得分

$ ./json-validate-test-suite.sh ./codegolf-474.py
score: 300/300

3

Scala-390个字符

import scala.util.parsing.combinator.JavaTokenParsers
object J extends JavaTokenParsers{def j=o|a
def o:Parser[Any]="{"~repsep(p,",")~"}"
def p=s~":"~v
def a:Parser[Any]="["~repsep(v,",")~"]"
def v=s|o|a|"true"|"false"|"null"
def s=stringLiteral
def n=floatingPointNumber}
object Main{def main(a:Array[String]){print(if(J.parseAll(J.j,readLine()).successful)"Valid"else"Invalid")}}

使用解析器组合器,这是毫无脑子的解决方案。从字面上看,写在1或2分钟内。无法获取验证器脚本,浏览器表示未找到服务器。


看起来是一个有趣的解决方案;验证程序链接已修复。
Armand 2012年

在Windows上有简单的方法吗?(没有cygwin或类似异端)
显示名称
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.