Regex เพื่อตรวจสอบความถูกต้องของ JSON


90

ฉันกำลังมองหา Regex ที่ช่วยให้ฉันตรวจสอบ json ได้

ฉันใหม่มากสำหรับ Regex และฉันรู้ดีพอว่าการแยกวิเคราะห์ด้วย Regex นั้นไม่ดี แต่สามารถใช้ตรวจสอบความถูกต้องได้หรือไม่


31
ทำไมต้องกังวลกับขั้นตอนการตรวจสอบความถูกต้องแยกต่างหาก? ภาษาส่วนใหญ่มีไลบรารี JSON ที่สามารถแยกวิเคราะห์ JSON และหากสามารถแยกวิเคราะห์ได้แสดงว่าถูกต้อง ถ้าไม่ห้องสมุดจะบอกคุณ
Epcylon

คุณต้องแยกวิเคราะห์ข้อความเพื่อตรวจสอบความถูกต้อง ...
Ken

3
@mario - ฉันไม่รู้ ... ฉันทุกคนที่ใช้ regex ในทางที่ผิดและเห็นใจอย่างยิ่งที่คุณคัดค้าน "regex ต้องตรงกับความเข้าใจผิดปกติ" - แต่ไม่ใช่คำถามที่เกี่ยวข้องกับงานในทางปฏิบัติ คำตอบที่ดีที่สุดคือความคิดเห็นของ Epcylon จริงๆ ... (การสนทนานี้อาจอยู่ในแชทหรือไม่)
Kobi

1
อีกกรณีการใช้งานจริงคือการค้นหานิพจน์ JSON ภายในสตริงที่ใหญ่กว่า หากคุณเพียงแค่ต้องการถามว่า "สตริงนี้คือวัตถุ JSON" ใช่แล้วไลบรารีการแยกวิเคราะห์ JSON น่าจะเป็นเครื่องมือที่ดีกว่า แต่ไม่พบวัตถุ JSON ภายในโครงสร้างที่ใหญ่กว่าสำหรับคุณ
Mark Amery

1
นี่ไม่ใช่คำตอบ แต่คุณสามารถใช้ส่วนนี้ของไลบรารี JSON-js ของ Crockfordได้ ใช้ regexes 4 รายการและรวมเข้าด้วยกันอย่างชาญฉลาด
imgx64

คำตอบ:


186

ใช่การตรวจสอบ regex ที่สมบูรณ์เป็นไปได้

การใช้งาน regex ที่ทันสมัยส่วนใหญ่อนุญาตให้ใช้นิพจน์ซ้ำซึ่งสามารถตรวจสอบโครงสร้างอนุกรม JSON ที่สมบูรณ์ได้ ข้อกำหนด json.orgทำให้ค่อนข้างตรงไปตรงมา

$pcre_regex = '
  /
  (?(DEFINE)
     (?<number>   -? (?= [1-9]|0(?!\d) ) \d+ (\.\d+)? ([eE] [+-]? \d+)? )    
     (?<boolean>   true | false | null )
     (?<string>    " ([^"\\\\]* | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9a-f]{4} )* " )
     (?<array>     \[  (?:  (?&json)  (?: , (?&json)  )*  )?  \s* \] )
     (?<pair>      \s* (?&string) \s* : (?&json)  )
     (?<object>    \{  (?:  (?&pair)  (?: , (?&pair)  )*  )?  \s* \} )
     (?<json>   \s* (?: (?&number) | (?&boolean) | (?&string) | (?&array) | (?&object) ) \s* )
  )
  \A (?&json) \Z
  /six   
';

มันทำงานได้ค่อนข้างดีใน PHP กับฟังก์ชั่น PCRE ควรใช้งานที่ไม่มีการแก้ไขใน Perl และสามารถปรับให้เข้ากับภาษาอื่น ๆ ได้อย่างแน่นอน นอกจากนี้ยังประสบความสำเร็จกับการทดสอบกรณี JSON

การตรวจสอบ RFC4627 ที่ง่ายขึ้น

วิธีง่ายคือตรวจสอบความสอดคล้องน้อยที่สุดตามที่ระบุไว้ในRFC4627 มาตรา 6 อย่างไรก็ตามมีวัตถุประสงค์เพื่อทดสอบความปลอดภัยและข้อควรระวังพื้นฐานเกี่ยวกับความไม่ถูกต้อง:

  var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
         text.replace(/"(\\.|[^"\\])*"/g, ''))) &&
     eval('(' + text + ')');

23
+1 มีสิ่งเลวร้ายมากมายในโลกจากผู้คนที่ไม่ได้รับไวยากรณ์ regex และใช้สิ่งนั้นในทางที่ผิดเพื่อเป็นสาเหตุให้เกลียดพวกเขา :(
NikiC

8
@mario ไม่แน่ใจว่าคุณคิดว่าฉันอยู่ในแผนก naysayers-departmentหรือเปล่า แต่ฉันไม่ใช่ โปรดทราบว่าคำแถลงของคุณ"การใช้ regex ที่ทันสมัยที่สุดอนุญาตให้ใช้นิพจน์ซ้ำ"เป็นที่ถกเถียงกันมาก AFAIK มีเพียง Perl, PHP และ. NET เท่านั้นที่มีความสามารถในการกำหนดรูปแบบการเรียกซ้ำ ฉันจะไม่เรียกสิ่งนั้นว่า "ส่วนใหญ่"
Bart Kiers

3
@ บาร์ต: ใช่นั่นเป็นเรื่องที่ถกเถียงกันอย่างถูกต้อง แดกดันเอ็นจิน Javascript regex ส่วนใหญ่ไม่สามารถใช้ regex แบบเรียกซ้ำเพื่อตรวจสอบ JSON (หรือเฉพาะกับวิธีแก้ปัญหาที่ซับซ้อนเท่านั้น) ดังนั้นถ้า regex == posix regex จะไม่ใช่ตัวเลือก อย่างไรก็ตามมันน่าสนใจที่สามารถใช้งานได้กับการใช้งานร่วมสมัย แม้จะมีกรณีการใช้งานจริงเพียงเล็กน้อย (แต่ความจริง libpcre ไม่ใช่เครื่องมือที่แพร่หลายในทุกที่) - สำหรับบันทึก: ฉันหวังว่าจะได้ป้ายการกลับรายการแบบสังเคราะห์ แต่การที่คุณไม่ได้รับการโหวตเพิ่มขึ้นจากแบนด์แวกสองสามตัวขัดขวางสิ่งนั้น : /
mario

4
ไม่ ฉันอยู่หลังป้าย Populist ซึ่งฉันต้องการ 20 โหวต แต่ยังคง 10 คะแนนสำหรับคำตอบของคุณ ดังนั้นในทางตรงกันข้ามการโหวตลงคะแนนในคำถามของคุณไม่ได้เป็นประโยชน์ต่อฉันสำหรับสิ่งนั้น
มาริโอ

2
เมื่อมองต่อไป regexp นี้มีปัญหาอื่น ๆ อีกมากมาย ตรงกับข้อมูล JSON แต่ข้อมูลที่ไม่ใช่ JSON บางส่วนก็ตรงกันเช่นกัน ตัวอย่างเช่นลิเทอรัลเดียวจะfalseจับคู่ในขณะที่ค่า JSON ระดับบนสุดต้องเป็นอาร์เรย์หรืออ็อบเจกต์ นอกจากนี้ยังมีปัญหามากมายในชุดอักขระที่อนุญาตในสตริงหรือในช่องว่าง
dolmen

32

ใช่มันเป็นความเข้าใจผิดกันว่านิพจน์ปกติสามารถจับคู่เพียงภาษาปกติ ในความเป็นจริงฟังก์ชั่น PCRE สามารถจับคู่ภาษาได้มากกว่าภาษาทั่วไปสามารถจับคู่ได้แม้กระทั่งภาษาที่ไม่มีบริบท! บทความของ Wikipedia เกี่ยวกับ RegExpsมีส่วนพิเศษเกี่ยวกับเรื่องนี้

JSON สามารถรับรู้โดยใช้ PCRE ได้หลายวิธี! @mario แสดงให้เห็นว่าหนึ่งในทางออกที่ดีในการใช้ subpatterns ชื่อและกลับอ้างอิง จากนั้นเขาก็ตั้งข้อสังเกตว่าควรจะมีวิธีการแก้ปัญหาโดยใช้รูปแบบ recursive (?R)นี่คือตัวอย่างของ regexp ที่เขียนด้วย PHP:

$regexString = '"([^"\\\\]*|\\\\["\\\\bfnrt\/]|\\\\u[0-9a-f]{4})*"';
$regexNumber = '-?(?=[1-9]|0(?!\d))\d+(\.\d+)?([eE][+-]?\d+)?';
$regexBoolean= 'true|false|null'; // these are actually copied from Mario's answer
$regex = '/\A('.$regexString.'|'.$regexNumber.'|'.$regexBoolean.'|';    //string, number, boolean
$regex.= '\[(?:(?1)(?:,(?1))*)?\s*\]|'; //arrays
$regex.= '\{(?:\s*'.$regexString.'\s*:(?1)(?:,\s*'.$regexString.'\s*:(?1))*)?\s*\}';    //objects
$regex.= ')\Z/is';

ฉันใช้(?1)แทน(?R)เพราะส่วนหลังอ้างอิงรูปแบบทั้งหมดแต่เรามี\Aและ\Zลำดับที่ไม่ควรใช้ในรูปแบบย่อย (?1)การอ้างอิงถึง regexp ที่ทำเครื่องหมายโดยวงเล็บด้านนอกสุด (นี่คือสาเหตุที่ตัวนอกสุด( )ไม่ขึ้นต้นด้วย?:) ดังนั้น RegExp จึงมีความยาว 268 อักขระ :)

/\A("([^"\\]*|\\["\\bfnrt\/]|\\u[0-9a-f]{4})*"|-?(?=[1-9]|0(?!\d))\d+(\.\d+)?([eE][+-]?\d+)?|true|false|null|\[(?:(?1)(?:,(?1))*)?\s*\]|\{(?:\s*"([^"\\]*|\\["\\bfnrt\/]|\\u[0-9a-f]{4})*"\s*:(?1)(?:,\s*"([^"\\]*|\\["\\bfnrt\/]|\\u[0-9a-f]{4})*"\s*:(?1))*)?\s*\})\Z/is

อย่างไรก็ตามสิ่งนี้ควรถือเป็น "การสาธิตเทคโนโลยี" ไม่ใช่วิธีแก้ปัญหาในทางปฏิบัติ ใน PHP ฉันจะตรวจสอบสตริง JSON ด้วยการเรียกใช้json_decode()ฟังก์ชัน (เช่นเดียวกับที่ @Epcylon ระบุไว้) ถ้าฉันจะใช้ JSON นั้น (หากผ่านการตรวจสอบแล้ว) นี่เป็นวิธีที่ดีที่สุด


1
การใช้\dเป็นอันตราย ในการใช้งาน regexp จำนวนมาก\dตรงกับนิยาม Unicode ของตัวเลขที่ไม่เพียง[0-9]แต่รวมสคริปต์ทางเลือกแทน
dolmen

@dolmen: คุณอาจจะพูดถูก แต่คุณไม่ควรแก้ไขตัวเองเป็นคำถาม แค่เพิ่มเป็นความคิดเห็นก็น่าจะเพียงพอแล้ว
Dennis Haarbrink

ฉันคิดว่า\dไม่ตรงกับหมายเลข Unicode ในการใช้งาน PCRE ของ PHP ตัวอย่างเช่น٩สัญลักษณ์ (0x669 หลักที่บ่งบอกภาษาอาหรับเก้า) จะจับคู่โดยใช้รูปแบบ#\p{Nd}#uแต่ไม่ใช่#\d#u
Hrant Khachatrian

@ hrant-khachatrian: ไม่ใช่เพราะคุณไม่ได้ใช้/uธง JSON เข้ารหัสเป็น UTF-8 สำหรับ regexp ที่เหมาะสมคุณควรใช้แฟล็กนั้น
dolmen

1
@dolmen ฉันใช้โมดิฟายเออuร์โปรดดูรูปแบบในความคิดเห็นก่อนหน้านี้อีกครั้ง :) สตริงตัวเลขและบูลีนตรงกันอย่างถูกต้องที่ระดับบนสุด คุณสามารถวาง regexp แบบยาวได้ที่นี่quanetic.com/Regexและลองด้วยตัวเอง
Hrant Khachatrian

14

เนื่องจากลักษณะการเรียกซ้ำของ JSON ( {...}-s ที่ซ้อนกัน) regex จึงไม่เหมาะที่จะตรวจสอบความถูกต้อง แน่นอนว่ารสชาติ regex บางอย่างสามารถจับคู่รูปแบบซ้ำได้* (และสามารถจับคู่ JSON ได้) แต่รูปแบบที่ได้นั้นดูน่ากลัวและไม่ควรใช้ในรหัสการผลิต IMO!

* โปรดระวังการใช้ regex จำนวนมากไม่สนับสนุนรูปแบบการเรียกซ้ำ ภาษาโปรแกรมยอดนิยมเหล่านี้รองรับรูปแบบการเรียกซ้ำ: Perl, .NET, PHP และ Ruby 1.9.2



16
@ all down ผู้มีสิทธิเลือกตั้ง: "regex ไม่เหมาะที่จะตรวจสอบ"ไม่ได้หมายความว่าเอ็นจิ้นregex บางตัวไม่สามารถทำได้ (อย่างน้อยก็คือสิ่งที่ฉันหมายถึง) แน่นอนว่าการใช้งาน regex บางอย่างสามารถทำได้แต่ใครก็ตามที่คิดว่าถูกต้องจะใช้โปรแกรมแยกวิเคราะห์ JSON เช่นเดียวกับถ้ามีคนถามว่าจะสร้างบ้านที่สมบูรณ์โดยใช้ค้อนเพียงอย่างเดียวฉันจะตอบว่าค้อนไม่เหมาะกับงานคุณต้องมีชุดเครื่องมือและเครื่องจักรที่สมบูรณ์ แน่นอนว่าคนที่มีความอดทนเพียงพอสามารถทำได้ด้วยค้อน
Bart Kiers

1
นี่อาจเป็นคำเตือนที่ถูกต้อง แต่ไม่สามารถตอบคำถามได้ Regex อาจไม่ใช่เครื่องมือที่ถูกต้อง แต่บางคนไม่มีทางเลือก เราถูกล็อกให้เป็นผลิตภัณฑ์ของผู้ขายที่ประเมินผลลัพธ์ของบริการเพื่อตรวจสอบความสมบูรณ์ของบริการและตัวเลือกเดียวที่ผู้ขายมีให้สำหรับการตรวจสอบความสมบูรณ์แบบกำหนดเองคือเว็บฟอร์มที่ยอมรับนิพจน์ทั่วไป ผลิตภัณฑ์ของผู้ขายที่ประเมินสถานะการบริการไม่ได้อยู่ภายใต้การควบคุมของทีมงานของฉัน สำหรับเราการประเมิน JSON ด้วย regex เป็นข้อกำหนดดังนั้นคำตอบของ "ไม่เหมาะสม" จึงไม่สามารถทำได้ (ฉันยังไม่ได้ลงคะแนนให้คุณ)
John

12

ฉันลองคำตอบของ @ mario แล้ว แต่มันไม่ได้ผลสำหรับฉันเพราะฉันดาวน์โหลดชุดทดสอบจาก JSON.org ( เก็บถาวร ) และมีการทดสอบที่ล้มเหลว 4 ครั้ง (fail1.json, fail18.json, fail25.json, fail27 json)

ฉันได้ตรวจสอบข้อผิดพลาดและพบว่าfail1.jsonถูกต้องจริง (ตามบันทึกของคู่มือและสตริงที่ถูกต้องRFC-7159ก็เป็น JSON ที่ถูกต้องเช่นกัน) ไฟล์fail18.jsonก็ไม่ใช่กรณีเช่นกันเนื่องจากมี JSON ที่ซ้อนกันอย่างถูกต้องจริง:

[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]

เหลือสองไฟล์: fail25.jsonและfail27.json:

["  tab character   in  string  "]

และ

["line
break"]

ทั้งสองมีอักขระที่ไม่ถูกต้อง ดังนั้นฉันจึงอัปเดตรูปแบบเช่นนี้ (อัปเดตรูปแบบย่อยของสตริง):

$pcreRegex = '/
          (?(DEFINE)
             (?<number>   -? (?= [1-9]|0(?!\d) ) \d+ (\.\d+)? ([eE] [+-]? \d+)? )
             (?<boolean>   true | false | null )
             (?<string>    " ([^"\n\r\t\\\\]* | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9a-f]{4} )* " )
             (?<array>     \[  (?:  (?&json)  (?: , (?&json)  )*  )?  \s* \] )
             (?<pair>      \s* (?&string) \s* : (?&json)  )
             (?<object>    \{  (?:  (?&pair)  (?: , (?&pair)  )*  )?  \s* \} )
             (?<json>   \s* (?: (?&number) | (?&boolean) | (?&string) | (?&array) | (?&object) ) \s* )
          )
          \A (?&json) \Z
          /six';

ตอนนี้สามารถผ่านการทดสอบทางกฎหมายทั้งหมดจากjson.orgได้แล้ว


ซึ่งจะจับคู่เฉพาะค่า JSON (สตริงบูลีนและตัวเลข) เช่นกันซึ่งไม่ใช่ออบเจ็กต์ / อาร์เรย์ JSON
kowsikbabu

4

เมื่อดูเอกสารสำหรับJSONดูเหมือนว่า regex สามารถเป็นสามส่วนได้หากเป้าหมายคือการตรวจสอบความเหมาะสม:

  1. สตริงเริ่มต้นและลงท้ายด้วย[]หรือ{}
    • [{\[]{1}...[}\]]{1}
  2. และ
    1. อักขระเป็นอักขระควบคุม JSON ที่อนุญาต (เพียงตัวเดียว)
      • ป ... [,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]
    2. หรือชุดอักขระที่มีอยู่ในไฟล์""
      • ป ... ".*?"

ทั้งหมดเข้าด้วยกัน: [{\[]{1}([,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]|".*?")+[}\]]{1}

ถ้าสตริง JSON มีnewlineตัวละครแล้วคุณควรใช้singlelineสวิทช์รสชาติ regex ของคุณเพื่อให้ตรงกับ. newlineโปรดทราบว่าการดำเนินการนี้จะไม่ล้มเหลวใน JSON ที่ไม่ดีทั้งหมด แต่จะล้มเหลวหากโครงสร้าง JSON พื้นฐานไม่ถูกต้องซึ่งเป็นวิธีตรงไปตรงมาในการตรวจสอบความถูกต้องพื้นฐานก่อนส่งต่อไปยังโปรแกรมแยกวิเคราะห์


1
regex ที่แนะนำมีพฤติกรรมย้อนรอยที่น่ากลัวในกรณีทดสอบบางอย่าง หากคุณลองรันบน "{" a ": false," b ": true," c ": 100," "json ที่ไม่สมบูรณ์นี้จะหยุดทำงานตัวอย่าง: regex101.com/r/Zzc6szการแก้ไขง่ายๆคือ : [{[] {1} ([,: {} [] 0-9. \ - + Eaeflnr-u \ n \ r \ t] | ". *?") + [}]] {1}
Toonijn

@Toonijn ฉันอัปเดตเพื่อแสดงความคิดเห็นของคุณ ขอบคุณ!
cjbarth

@cjbarth เวอร์ชันที่ปรับเปลี่ยนเล็กน้อยนี้ใช้งานได้อย่างสมบูรณ์แบบสำหรับกรณีการใช้งานของฉันในการค้นหาโครงสร้างแบบ JSON ทั้งหมดในข้อความ (ใช้กับไฟล์ HTML ทั่วโลกในกรณีของฉัน):[{\[]{1}([,:{}\[\]0-9.\-+A-zr-u \n\r\t]|".*:?")+[}\]]{1}
C2BB

3

ฉันสร้างการใช้งาน Ruby ของโซลูชันของ Mario ซึ่งใช้งานได้:

# encoding: utf-8

module Constants
  JSON_VALIDATOR_RE = /(
         # define subtypes and build up the json syntax, BNF-grammar-style
         # The {0} is a hack to simply define them as named groups here but not match on them yet
         # I added some atomic grouping to prevent catastrophic backtracking on invalid inputs
         (?<number>  -?(?=[1-9]|0(?!\d))\d+(\.\d+)?([eE][+-]?\d+)?){0}
         (?<boolean> true | false | null ){0}
         (?<string>  " (?>[^"\\\\]* | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9a-f]{4} )* " ){0}
         (?<array>   \[ (?> \g<json> (?: , \g<json> )* )? \s* \] ){0}
         (?<pair>    \s* \g<string> \s* : \g<json> ){0}
         (?<object>  \{ (?> \g<pair> (?: , \g<pair> )* )? \s* \} ){0}
         (?<json>    \s* (?> \g<number> | \g<boolean> | \g<string> | \g<array> | \g<object> ) \s* ){0}
       )
    \A \g<json> \Z
    /uix
end

########## inline test running
if __FILE__==$PROGRAM_NAME

  # support
  class String
    def unindent
      gsub(/^#{scan(/^(?!\n)\s*/).min_by{|l|l.length}}/u, "")
    end
  end

  require 'test/unit' unless defined? Test::Unit
  class JsonValidationTest < Test::Unit::TestCase
    include Constants

    def setup

    end

    def test_json_validator_simple_string
      assert_not_nil %s[ {"somedata": 5 }].match(JSON_VALIDATOR_RE)
    end

    def test_json_validator_deep_string
      long_json = <<-JSON.unindent
      {
          "glossary": {
              "title": "example glossary",
          "GlossDiv": {
                  "id": 1918723,
                  "boolean": true,
                  "title": "S",
            "GlossList": {
                      "GlossEntry": {
                          "ID": "SGML",
                "SortAs": "SGML",
                "GlossTerm": "Standard Generalized Markup Language",
                "Acronym": "SGML",
                "Abbrev": "ISO 8879:1986",
                "GlossDef": {
                              "para": "A meta-markup language, used to create markup languages such as DocBook.",
                  "GlossSeeAlso": ["GML", "XML"]
                          },
                "GlossSee": "markup"
                      }
                  }
              }
          }
      }
      JSON

      assert_not_nil long_json.match(JSON_VALIDATOR_RE)
    end

  end
end

การใช้ \ d เป็นสิ่งที่อันตราย ในการใช้ regexp จำนวนมาก \ d ตรงกับนิยาม Unicode ของตัวเลขที่ไม่ใช่แค่ [0-9] แต่รวมถึงสคริปต์ทางเลือกแทน ดังนั้นหากการสนับสนุน Unicode ใน Ruby ยังคงใช้งานไม่ได้คุณต้องแก้ไข regexp ในโค้ดของคุณ
dolmen

เท่าที่ฉันทราบ Ruby ใช้ PCRE ซึ่ง \ d ไม่ตรงกับคำจำกัดความของ "หลัก" ทั้งหมดของ Unicode หรือคุณกำลังบอกว่ามันควร?
pmarreck

ยกเว้นว่าจะไม่มี ผลบวกเท็จ: "\ x00", [True] ลบเท็จ: "\ u0000", "\ n" แฮงค์: "[{" ": [{" ": [{" ":" (ซ้ำ 1000x)
NST

ไม่ยากเกินไปที่จะเพิ่มเป็นกรณีทดสอบแล้วปรับแต่งรหัสเพื่อผ่าน ทำยังไงให้มันไม่ระเบิดสแต็คที่มีความลึกมากกว่า
1,000+

1

สำหรับ "สตริงและตัวเลข" ฉันคิดว่านิพจน์ทั่วไปบางส่วนสำหรับตัวเลข:

-?(?:0|[1-9]\d*)(?:\.\d+)(?:[eE][+-]\d+)?

ควรเป็นแทน:

-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?

เนื่องจากส่วนทศนิยมของตัวเลขเป็นทางเลือกและอาจปลอดภัยกว่าที่จะหลีกเลี่ยง-สัญลักษณ์[+-]เนื่องจากมีความหมายพิเศษระหว่างวงเล็บ


การใช้\dเป็นอันตราย ในการใช้งาน regexp จำนวนมาก\dตรงกับนิยาม Unicode ของตัวเลขที่ไม่เพียง[0-9]แต่รวมสคริปต์ทางเลือกแทน
dolmen

มันดูแปลกไปหน่อยที่ -0 เป็นตัวเลขที่ถูกต้อง แต่ RFC 4627 อนุญาตและนิพจน์ทั่วไปของคุณก็สอดคล้องกับมัน
สิ้นสุด

1

เครื่องหมายจุลภาคต่อท้ายในอาร์เรย์ JSON ทำให้ Perl 5.16 ของฉันหยุดทำงานอาจเป็นเพราะมันยังคงย้อนกลับ ฉันต้องเพิ่มคำสั่งยุติการย้อนรอย:

(?<json>   \s* (?: (?&number) | (?&boolean) | (?&string) | (?&array) | (?&object) )(*PRUNE) \s* )
                                                                                   ^^^^^^^^

ด้วยวิธีนี้เมื่อระบุโครงสร้างที่ไม่ใช่ 'ทางเลือก' ( *หรือ?) แล้วก็ไม่ควรลองย้อนรอยเพื่อพยายามระบุว่าเป็นสิ่งอื่น


0

ตามที่เขียนไว้ข้างต้นหากภาษาที่คุณใช้มีไลบรารี JSON มาด้วยให้ใช้เพื่อลองถอดรหัสสตริงและตรวจจับข้อยกเว้น / ข้อผิดพลาดหากล้มเหลว! หากภาษาไม่มี (เพิ่งมีกรณีเช่นนี้กับ FreeMarker) อย่างน้อย regex ต่อไปนี้ก็สามารถตรวจสอบความถูกต้องขั้นพื้นฐานได้ (ซึ่งเขียนขึ้นเพื่อให้ PHP / PCRE สามารถทดสอบได้ / ใช้งานได้สำหรับผู้ใช้จำนวนมากขึ้น) มันไม่สามารถเข้าใจผิดได้เหมือนกับวิธีแก้ปัญหาที่ยอมรับ แต่ก็ไม่น่ากลัวเช่นกัน =):

~^\{\s*\".*\}$|^\[\n?\{\s*\".*\}\n?\]$~s

คำอธิบายสั้น ๆ :

// we have two possibilities in case the string is JSON
// 1. the string passed is "just" a JSON object, e.g. {"item": [], "anotheritem": "content"}
// this can be matched by the following regex which makes sure there is at least a {" at the
// beginning of the string and a } at the end of the string, whatever is inbetween is not checked!

^\{\s*\".*\}$

// OR (character "|" in the regex pattern)
// 2. the string passed is a JSON array, e.g. [{"item": "value"}, {"item": "value"}]
// which would be matched by the second part of the pattern above

^\[\n?\{\s*\".*\}\n?\]$

// the s modifier is used to make "." also match newline characters (can happen in prettyfied JSON)

หากฉันพลาดสิ่งที่จะทำลายสิ่งนี้โดยไม่ได้ตั้งใจฉันขอบคุณสำหรับความคิดเห็น!


0

Regex ที่ตรวจสอบ JSON ธรรมดาไม่ใช่ JSONArray

ตรวจสอบความถูกต้องของคีย์ (สตริง): ค่า (สตริง, จำนวนเต็ม, [{คีย์: ค่า}, {คีย์: ค่า}], {คีย์: ค่า})

^\{(\s|\n\s)*(("\w*"):(\s)*("\w*"|\d*|(\{(\s|\n\s)*(("\w*"):(\s)*("\w*(,\w+)*"|\d{1,}|\[(\s|\n\s)*(\{(\s|\n\s)*(("\w*"):(\s)*(("\w*"|\d{1,}))((,(\s|\n\s)*"\w*"):(\s)*("\w*"|\d{1,}))*(\s|\n)*\})){1}(\s|\n\s)*(,(\s|\n\s)*\{(\s|\n\s)*(("\w*"):(\s)*(("\w*"|\d{1,}))((,(\s|\n\s)*"\w*"):(\s)*("\w*"|\d{1,}))*(\s|\n)*\})?)*(\s|\n\s)*\]))((,(\s|\n\s)*"\w*"):(\s)*("\w*(,\w+)*"|\d{1,}|\[(\s|\n\s)*(\{(\s|\n\s)*(("\w*"):(\s)*(("\w*"|\d{1,}))((,(\s|\n\s)*"\w*"):(\s)*("\w*"|\d{1,}))*(\s|\n)*\})){1}(\s|\n\s)*(,(\s|\n\s)*\{(\s|\n\s)*(("\w*"):(\s)*(("\w*"|\d{1,}))((,(\s|\n\s)*"\w*"):("\w*"|\d{1,}))*(\s|\n)*\})?)*(\s|\n\s)*\]))*(\s|\n\s)*\}){1}))((,(\s|\n\s)*"\w*"):(\s)*("\w*"|\d*|(\{(\s|\n\s)*(("\w*"):(\s)*("\w*(,\w+)*"|\d{1,}|\[(\s|\n\s)*(\{(\s|\n\s)*(("\w*"):(\s)*(("\w*"|\d{1,}))((,(\s|\n\s)*"\w*"):(\s)*("\w*"|\d{1,}))*(\s|\n)*\})){1}(\s|\n\s)*(,(\s|\n\s)*\{(\s|\n\s)*(("\w*"):(\s)*(("\w*"|\d{1,}))((,(\s|\n\s)*"\w*"):(\s)*("\w*"|\d{1,}))*(\s|\n)*\})?)*(\s|\n\s)*\]))((,(\s|\n\s)*"\w*"):(\s)*("\w*(,\w+)*"|\d{1,}|\[(\s|\n\s)*(\{(\s|\n\s)*(("\w*"):(\s)*(("\w*"|\d{1,}))((,(\s|\n\s)*"\w*"):(\s)*("\w*"|\d{1,}))*(\s|\n)*\})){1}(\s|\n\s)*(,(\s|\n\s)*\{(\s|\n\s)*(("\w*"):(\s)*(("\w*"|\d{1,}))((,(\s|\n\s)*"\w*"):("\w*"|\d{1,}))*(\s|\n)*\})?)*(\s|\n\s)*\]))*(\s|\n\s)*\}){1}))*(\s|\n)*\}$

ข้อมูลตัวอย่างที่ตรวจสอบโดย JSON นี้

{
"key":"string",
"key": 56,
"key":{
        "attr":"integer",
        "attr": 12
        },
"key":{
        "key":[
            {
                "attr": 4,
                "attr": "string"
            }
        ]
     }
}


-2

ฉันตระหนักดีว่านี่มาจาก 6 ปีที่แล้ว อย่างไรก็ตามฉันคิดว่ามีวิธีแก้ปัญหาที่ไม่มีใครพูดถึงว่าง่ายกว่า regexing

function isAJSON(string) {
    try {
        JSON.parse(string)  
    } catch(e) {
        if(e instanceof SyntaxError) return false;
    };  
    return true;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.