Schreiben Sie einen JSON-Validator

12

Schreiben Sie ein Programm, das feststellt, ob seine Eingabe JSON- gültig ist .

  • Eingabe: ASCII-Text:[\x00-\x7F]*

    Hinweis: Wenn ASCII problematisch ist, können Sie eine andere Codierung verwenden, diese jedoch in Ihrem Beitrag angeben.

  • Ausgabe: Valid oder Invalid. Nachgestellte Zeilenumbrüche können weggelassen werden.

  • Beispiel:

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

    • Verwenden Sie keine JSON-Analysebibliothek.
    • Teilkorrekte Lösungen sind erlaubt, aber verpönt.
    • Veröffentlichen Sie Ihre Testsuite (siehe unten).

Die kürzeste richtige Lösung gewinnt.

Bitte führen Sie json-validate-test-suite.sh in Ihrem Programm aus und geben Sie Ihre Punktzahl ein. Beispiel:

$ ./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

Ressourcen:


Die JSON-Grammatik lautet wie folgt:

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

Außerdem kann vor oder nach den sechs Strukturzeichen ein Leerzeichen stehen {}[]:,

ws = [\t\n\r ]*

Beachten Sie Folgendes:

  • Seien Sie vorsichtig mit Funktionen wie isspace(). Whitespace in JSON ist [\t\n\r ], isspace()behandelt aber auch \v(vertikale Registerkarte) und \f(Formularvorschub) als Leerzeichen. Obwohl Word es hat, das mehr als nur akzeptierenisdigit() kann , sollte es in Ordnung sein, es hier zu verwenden, da wir davon ausgehen, dass die Eingabe in ASCII erfolgt.[0-9]
  • \x7Fist technisch gesehen ein Steuerzeichen, wird jedoch im JSON-RFC nicht erwähnt (nur erwähnt [\x00-\x1F]), und die meisten JSON-Parser akzeptieren \x7FZeichen in Zeichenfolgen. Aufgrund dieser Mehrdeutigkeit können die Lösungen entscheiden, ob sie diese akzeptieren oder nicht.
Joey Adams
quelle
7
Ihre Anmerkung "teilweise korrekte Lösungen erlaubt" lässt mich träumen, einen regulären Ausdruck aus einem genetischen Algorithmus zu extrahieren. Ich muss verrückt sein.
JB
@JB: Das wäre großartig.
Joey Adams
Nur neugierig, warum wird {key: "value"}JSON für ungültig erklärt? Es ist gültiges Javascript.
HoLyVieR
@HoLyVieR: Ich stelle mir vor, dass JSON für Implementierer einfacher zu analysieren und weniger mehrdeutig ist. Ich bin mir auch nicht sicher, ob mir diese Einschränkung gefällt.
Joey Adams
Hat jemand eine Kopie des Validator-Skripts?
Armand

Antworten:

7

PHP: 297 285 264 253 Zeichen

<?=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';

Punktzahl: 300/300

Dies ist eine vollständige, rekursive Implementierung der JSON-Grammatik.

Aufgrund der nowdoc- Syntax funktioniert es nur mit PHP ≥ 5.3 (heredoc hätte alles verdoppeln müssen \).

Lesbare Version:

(Dies ist der gleiche reguläre Ausdruck mit benannten Erfassungsgruppen und erweiterter Syntax):

#!/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';
}
Arnaud Le Blanc
quelle
Beeindruckend. `` `` `
Nathan Osman
Sie müssen die <?phpIMO einbeziehen.
Anonymer Feigling
Hinzugefügt. 264 Zeichen jetzt :-)
Arnaud Le Blanc
5

Python - 340 314 299 292 Zeichen

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'

Ergebnis

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

Scala - 390 Zeichen

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")}}

Dies ist eine einfache Lösung, die Parser-Kombinatoren verwendet. Im wahrsten Sinne des Wortes in 1 oder 2 Minuten geschrieben. Das Überprüfungsskript kann nicht abgerufen werden. Der Browser hat gemeldet, dass der Server nicht gefunden wurde.

Anzeigename
quelle
sieht nach einer interessanten Lösung aus; Validator-Link wurde behoben.
Armand
Gibt es eine einfache Möglichkeit, dies unter Windows zu tun? (ohne Cygwin oder ähnliche Häresie)
Anzeigename