再帰的 正規表現JSON Validatorサイボウズ・ラボ株式会社竹迫 良範<takesako@shibuya.pm.org>
(?R)
再帰的正規表現でJSON Validatorを作ってみたPCREの記法(?R)(?0)(?1)を使うテクニック$json =~ /\A ( \s* (?:"(?:[^"\\]*|\\["\\bfnrt\/]|\\u[0-9A-Fa-f]{4})*"  | -? (?= [1-9]|0(?!\d) ) \d+ (?:\.\d+)? (?:[eE] [+-]? \d+)?   | true | false | null  | \[  (?:  (?1)  (?: , (?1)  )*  )?  \s* \]  | \{ (?: \s*"(?:[^"\\]*|\\["\\bfnrt\/]|\\u[0-9A-Fa-f]{4})*"\s*:(?1)     (?:,\s*"(?:[^"\\]*|\\["\\bfnrt\/]|\\u[0-9A-Fa-f]{4})*"\s*:(?1)  )*)? \s*\} ) \s*)\Z/sx;
JSONとは
JSONとはJavaScript Object NotationJavaScriptの記法を元にしたデータ記述用言語元々はJavaScriptのサブセットとして考案varobj = eval(  "(" + json_text + ")"  );JSON文字列を evalすると JavaScript object になる[    { "id" : 1001 , "name" : "foo" },     { "id" : 1002 , "name" : "bar" }]
JavaScript で受け取った JSON を evalすると…そのまま evalするのは大変危険「山田太郎(正常系)」{ "name" : "山田太郎=> (正常系" }「山田  ”}),alert(24)//XSS」{ "name" : "山田"}),alert(24)//太郎" }varjson_text = (  { "name" : "  山田"}, alert(24);//XSS " });varobj = eval("(" + json_text + ")");
CVE-2007-3227:JSON における XSS 脆弱性#to_jsonのHTMLエスケープ漏れでXSSが発生http://dev.rubyonrails.org/ticket/8371
JSONの規格(データ交換フォーマット)RFC4627 による定義The application/json Media Type forJavaScript Object Notation (JSON)ECMA-262 による定義ECMA-262 ECMAScript言語仕様 5th edition15.12 The JSON object [PDF]ISO/IEC 16262:2011他のプログラミング言語の JSON parserPHP, Python, Java, Perl, C/C++...http://json.org/
JSON の構成要素JSON stringJSON numberJSON arrayJSON objectJSON value特別な値3つtruefalsenull
JSON string の定義例: "abc", "\t\n", "あ", "\u3042"A string is a collection of zero or more Unicode characters, wrapped in double quotes, using backslash escapes. A character is represented as a single character string.
JSON number の定義例: 0, 1, -2, 3.14, 9e3, 9000A number is very much like a C or Java number, except that the octal and hexadecimal formats are not used.
JSON array の定義例:["a", "b", "c"]An array is an ordered collection of values. An array begins with [ (left bracket) and ends with ] (right bracket). Values are separated by , (comma).
JSON object の定義例:{"string": value, "key": value}An object is an unordered set of name/value pairs. An object begins with { (left brace) and ends with } (right brace). Each name is followed by : (colon) and the name/value pairs are separated by , (comma).
JSON value の定義例:"abc", 123, {}, [], true, false, nullA value can be a string in double quotes, or a number, or true or false or null, or an object or an array. These structures can be nested.[ [], [1, 2], ["a", "b"], {}, {"x": {"y": "z"}} ]
演習問題
Q. 以下の JSON は正しいフォーマットか?(1) JSON object のキーは "string"{ apple: 1, beer: 2 }{ "apple": 1, "beer": 2 }
Q. 以下の JSON は正しいフォーマットか?(2) 複数 value のカンマ区切り(最後){  "name"   : "TAKESAKO, Yoshinori",   "E-mail" : "takesako@labs.cybozu.co.jp",}{  "name"   : "TAKESAKO, Yoshinori",   "E-mail" : "takesako@labs.cybozu.co.jp"}
Q. 以下の JSON は正しいフォーマットか?(3) JSON string の引用符は "" のみ[ 0, 1, 2, 'abc', 'string' ][ 0, 1, 2, "abc", "string" ]
Q. 以下の JSON は正しいフォーマットか?(4) JSON number の符号に + はない[ -3, 3.14, 1.23e2, +123.456 ][ -3, 3.14, 1.23e2,  123.456 ]
Q. 以下の JSON は正しいフォーマットか?(5) JavaScript comment は使用できない[{ /* Bookmark */  "url": "http://cybozu.co.jp/",  "memo": "Cybozu HP" // title}][{  "url": "http://cybozu.co.jp/",  "memo": "Cybozu HP"}]
Q. 以下の JSON は正しいフォーマットか?(6) JSON number は10進数のみ[  { "file": "a.out", "chmod": 0775 },  { "file": "a.cpp", "chmod": 0644 }][  { "file": "a.out", "chmod": 509 },  { "file": "a.cpp", "chmod": 420 }]
Q. 以下の JSON は正しいフォーマットか?(7) string number 以外の JSON value[ "Boolean", True, False, Null ][ "Boolean", true, false, null ]
Q. 以下の JSON は正しいフォーマットか?(8) Unicode 文字の扱い{ "a": "aあA", "i": "i\u3044I" }{ "a":"a\u3042A", "i":"i\u3044I" }
Q. 以下の JSON は正しいフォーマットか?(9) /のエスケープ"<script src='/jquery.js'></script>""<script src='/jquery.js'><\/script>"
正規表現でチェックできる?
Perl で PCRE 拡張の記法を使う(?(DEFINE)	(?<foo> regexp1)			(?<bar> regexp2) … )(?&foo) (?&bar)$json =~ /(?(DEFINE)(?<string>  (?:[^"\\]* | \\ ["\\bfnrt\/] | \\u[0-9A-Fa-f]{4} )* " )(?<number>  -? (?=[1-9]|0(?!\d))\d+(?:\.\d+)? (?:[eE] [+-]? \d+)? )     (?<boolean>   true | false | null )(?<array>     \[  (?:  (?&json)  (?: , (?&json)  )*  )?  \s* \] )     (?<pair>      \s* (?&string) \s* : (?&json)  )     (?<object>    \{  (?:  (?&pair)  (?: , (?&pair)  )*  )?  \s* \} )(?<json>  \s* (?: (?&number) | (?&boolean) | (?&string) | (?&array)  | (?&object)  ) \s* )) \A (?&json) \Z/sx;
これはわかりやすい
自分自身の正規表現にマッチ (?R)PCREの記法(?R)がPerlでも使える!“{{{}}}” にマッチ“xxxx{{{}}}}}}}zzzzzz” にもマッチ以下の正規表現だとネストしてくれない…/\{(?R)*\}//^ \{(?R)*\} $/
(?R)(?0)(?1)(?2)・・・が使える!任意のキャプチャ部分の再帰ができる/\{(?R)*\}//\{(?0)*\}//(\{(?1)*\})//^(\{(?1)*\})$/
JSON Validator を作ってみるPCREの記法(?1)を使うテクニック$json =~ /\A ( \s* (?:"(?:[^"\\]*|\\["\\bfnrt\/]|\\u[0-9A-Fa-f]{4})*"  | -? (?= [1-9]|0(?!\d) ) \d+ (?:\.\d+)? (?:[eE] [+-]? \d+)?   | true | false | null  | \[  (?:  (?1)  (?: , (?1)  )*  )?  \s* \]  | \{(?: \s*"(?:[^"\\]*|\\["\\bfnrt\/]|\\u[0-9A-Fa-f]{4})*"\s*:(?1)(?:,\s*"(?:[^"\\]*|\\["\\bfnrt\/]|\\u[0-9A-Fa-f]{4})*"\s*:(?1)    )* )? \s* \} ) \s*)\Z/sx;
再帰的正規表現便利也


再帰的 正規表現JSON Validator