Tulis validator JSON

12

Tulis program yang menentukan apakah inputnya JSON yang valid .

  • Input: teks ASCII:[\x00-\x7F]*

    Catatan: jika ASCII bermasalah, silakan gunakan pengkodean lain, tetapi tunjukkan dalam posting Anda.

  • Keluaran: Valid atau Invalid. Mengejar baris baru dapat dihilangkan.

  • Contoh:

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

    • Jangan gunakan parsing pustaka JSON.
    • Solusi yang sebagian benar diizinkan, tetapi disukai.
    • Posting skor test suite Anda (lihat di bawah).

The terpendek yang benar menang solusi.

Silakan jalankan json-validate-test-suite.sh di program Anda, dan poskan skor Anda. Contoh:

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

Sumber:

  • json.org - Definisi ringkas tata bahasa JSON dengan gambar yang mudah diikuti.
  • RFC 4627 - Spesifikasi JSON
  • json-validate.c - Implementasi 200-line yang lolos dari testuite.

Tata bahasa JSON adalah sebagai berikut:

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

Juga, spasi putih dapat muncul sebelum atau sesudah salah satu dari enam karakter struktural {}[]:,

ws = [\t\n\r ]*

Ingatlah yang berikut:

  • Hati-hati dengan fungsi seperti isspace(). Spasi di JSON adalah [\t\n\r ], tetapi isspace()juga memperlakukan \v(tab vertikal) dan \f(form feed) sebagai ruang. Meskipun ada kata yang isdigit()dapat menerima lebih dari sekadar[0-9] , seharusnya boleh digunakan di sini, karena kami menganggap input ada di ASCII.
  • \x7Fsecara teknis karakter kontrol, tetapi JSON RFC tidak menyebutkannya (hanya menyebutkannya [\x00-\x1F]), dan sebagian besar parser JSON cenderung menerima \x7Fkarakter dalam string. Karena ambiguitas ini, solusi dapat memilih untuk menerimanya atau tidak.
Joey Adams
sumber
7
Catatan "solusi yang sebagian benar diizinkan" membuat saya bermimpi mengekstraksi regex dari algoritma genetika. Saya pasti sudah gila.
JB
@ JK: Itu akan luar biasa.
Joey Adams
Hanya ingin tahu, mengapa {key: "value"}menganggap JSON tidak valid? Itu adalah javascript yang valid.
HoLyVieR
@HoLyVieR: Saya bayangkan JSON akan lebih mudah untuk diuraikan dan kurang ambigu untuk implementor. Saya tidak yakin saya suka batasan ini juga.
Joey Adams
Adakah yang mendapat salinan skrip validator?
Armand

Jawaban:

7

PHP: 297 285 264 253 karakter

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

skor: 300/300

Ini adalah implementasi penuh, tata bahasa JSON tata bahasa.

Ini hanya bekerja pada PHP ≥ 5.3 karena sintaks nowdoc (heredoc akan diperlukan untuk menggandakan semua \).

Versi yang dapat dibaca:

(ini adalah regex yang sama, dengan kelompok tangkapan bernama dan sintaks yang diperluas):

#!/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
sumber
Wow. `` `` ``
Nathan Osman
Anda harus memasukkan <?phpIMO.
pengecut anonim
Ditambahkan. 264 karakter sekarang :-)
Arnaud Le Blanc
5

Python - 340 314 299 292 karakter

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'

skor

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

Scala - 390 karakter

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

Ini adalah no-brainer soluton, menggunakan pengurai parser. Ditulis dalam 1 atau 2 menit, secara harfiah. Tidak dapat memperoleh skrip validator, browser mengatakan server itu tidak ditemukan.

Nama tampilan
sumber
terlihat seperti solusi yang menarik; tautan validator telah diperbaiki.
Armand
Apakah ada cara sederhana untuk melakukannya di Windows? (tanpa cygwin atau bid'ah serupa)
Nama Tampilan