เขียนตัวตรวจสอบ 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.org - คำจำกัดความที่รัดกุมของไวยากรณ์ JSON พร้อมรูปภาพที่ติดตามได้ง่าย
  • RFC 4627 - ข้อกำหนด JSON
  • json-validate.c - การใช้งาน 200 บรรทัดที่ผ่านการทดสอบไซต์

ไวยากรณ์ 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(ฟีดฟอร์ม) เป็นพื้นที่ แม้ว่า word มีคำที่isdigit()สามารถยอมรับได้มากกว่าเพียงแค่[0-9]ควรใช้ที่นี่เนื่องจากเราถือว่าข้อมูลเป็น ASCII
  • \x7Fในทางเทคนิคเป็นอักขระควบคุม แต่ JSON RFC ไม่ได้พูดถึงมัน (เป็นเพียงการกล่าวถึง[\x00-\x1F]) และตัวแยกวิเคราะห์ JSON ส่วนใหญ่มักจะยอมรับ\x7Fอักขระในสตริง เนื่องจากความกำกวมนี้โซลูชันอาจเลือกที่จะยอมรับหรือไม่เลือก

7
โน้ต "การแก้ปัญหาที่ถูกต้องเพียงบางส่วน" ของคุณทำให้ฉันใฝ่ฝันที่จะดึง regex ออกมาจากอัลกอริทึมทางพันธุกรรม ฉันจะต้องบ้า
JB

@JB: นั่นจะยอดเยี่ยม
Joey Adams

แค่สงสัยว่าทำไม{key: "value"}JSON ถึงไม่ถูกต้อง เป็นจาวาสคริปต์ที่ถูกต้อง
HoLyVieR

@HoLyVieR: ฉันคิดว่ามันจะทำให้ JSON แยกวิเคราะห์ได้ง่ายขึ้นและคลุมเครือน้อยลงสำหรับผู้ดำเนินการ ฉันไม่แน่ใจว่าฉันชอบข้อ จำกัด นี้เช่นกัน
Joey Adams

ใครมีสำเนาของสคริปต์ตัวตรวจสอบ
อาร์มันด์

คำตอบ:


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 แบบเรียกซ้ำ

มันทำงานได้เฉพาะใน PHP ≥ 5.3 เนื่องจากnowdocไวยากรณ์ (heredoc จะต้องไปคู่ทั้งหมด\)

รุ่นที่อ่านได้:

(นี่คือ regex เดียวกันโดยมีกลุ่มการดักจับที่กำหนดชื่อและไวยากรณ์เพิ่มเติม):

#!/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 chars ทันที :-)
Arnaud Le Blanc

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

สกาล่า - 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")}}

นี่คือโซลูตรอนที่ไม่มีเกมง่ายๆโดยใช้ตัวแยกวิเคราะห์ parser เขียนใน 1 หรือ 2 นาทีอย่างแท้จริง ไม่สามารถรับสคริปต์ตัวตรวจสอบความถูกต้องเบราว์เซอร์กล่าวว่าไม่พบเซิร์ฟเวอร์


ดูเหมือนว่าทางออกที่น่าสนใจ; ลิงก์ตัวตรวจสอบได้รับการแก้ไขแล้ว
อาร์มันด์

มีวิธีง่ายๆในการทำบน Windows หรือไม่? (ไม่มี cygwin หรือบาปคล้ายกัน)
ชื่อที่แสดง
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.