JSONバリデーターを書く


12

入力が有効なJSONかどうかを判断するプログラムを作成します。

  • 入力: ASCIIテキスト:[\x00-\x7F]*

    注:ASCIIに問題がある場合は、別のエンコードを使用しても構いませんが、投稿でそれを示してください。

  • 出力: ValidまたはInvalid。末尾の改行は省​​略できます。

  • 例:

    $ 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]+)?

また、空白は、6つの構造文字の前または後に表示できます。 {}[]:,

ws = [\t\n\r ]*

次のことに注意してください。

  • などの関数には注意してくださいisspace()。JSONに空白がある[\t\n\r ]が、isspace()また、おやつ\v(垂直タブ)と\f空間として(改)。wordには、以上のものisdigit()を受け入れる[0-9]ことができるものがありますが、入力はASCIIであると想定しているため、ここで使用しても大丈夫です。
  • \x7F技術的には制御文字ですが、JSON RFCはそれを言及しておらず(言及しているだけです[\x00-\x1F])、ほとんどのJSONパーサーは\x7F文字列の文字を受け入れる傾向があります。このあいまいさのため、ソリューションはそれらを受け入れるかどうかを選択できます。

7
あなたの「許可された部分的に正しい解」のメモは、遺伝的アルゴリズムから正規表現を抽出する夢を私に与えています。私は非常識でなければなりません。
— JB

@JB:それは素晴らしいことです。
— ジョーイアダムス

好奇心が強い、なぜ{key: "value"}無効なJSONを考慮するのですか?有効なjavascriptです。
— -HoLyVieR

@HoLyVieR:JSONの解析が容易になり、実装者にとって曖昧さが少なくなると思います。私もこの制限が好きかどうかわかりません。
— ジョーイアダムス

誰でも検証スクリプトのコピーを手に入れましたか?
— アルマン

回答:


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構文により、5.3以上のPHPでのみ動作します(heredocはすべてを2倍にする必要があります)\)。

読み取り可能なバージョン:

(これは、名前付きキャプチャグループと拡張構文を使用した同じ正規表現です):

#!/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';
}

ワオ。`` `` ``
— ネイサンオスマン

<?phpIMO を含める必要があります。
— 匿名の

追加。現在264文字:
— アルノールブラン

5

Pythonの- 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分で書かれます。検証スクリプトを取得できません、ブラウザはサーバーが見つからないと言いました。


興味深い解決策のように見えます。検証リンクが修正されました。
— アルマン

Windowsでそれを行う簡単な方法はありますか?(cygwinまたは類似の異端なし)
— 表示名
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.