![Rubyを256倍使うための本 無道編 Rubyを256倍使うための本 無道編](http://ecx.images-amazon.com/images/I/514H6QV4PTL._SL160_.jpg)
- 作者: 青木峰郎
- 出版社/メーカー: アスキー
- 発売日: 2001/02
- メディア: 単行本
- 購入: 4人 クリック: 44回
- この商品を含むブログ (57件) を見る
サンプルをいろいろ直すのが(手作業でパッチとか)めんどくさかった…と思うのは、日ごろスポイルされているせいかも。
JSONパーサも1時間くらいで(コピペで)作れたし、インタプリタを本格的に作成するのならともかく、データ構造をパースするのには日常的に活用できると思う。
拡張ライブラリ周りはもうすこし勉強しないと…
raccの練習ってことで、JSONのRFCを見ながらJSONパーサを作ってみた。
追記
yyparseを使うように修正。
こっちのほうがいい感じ。
追記2
って、よくみたら、エスケープされた文字列を元に戻してない…
後で直そう。
class JsonParser options no_result_var rule json_text : ws object ws { val[1] } | ws array ws { val[1] } ws : | ws SPACE value : FALSE | NULL | TRUE | object | array | NUMBER | STRING object : '{' ws '}' { {} } | '{' ws members ws '}' { h = {} val[2].each {|k,v| h[k] = v } h } members : member { [ val[0] ] } | members ws ',' ws member { val[0] << val[4] } member : STRING ws ':' ws value { [ val[0], val[4] ] } array : '[' ws ']' { [] } | '[' ws values ws ']' { val[2] } values : value { [ val[0] ] } | values ws ',' ws value { val[0] << val[4] } end ---- header require 'strscan' ---- inner R_SPACE = /\A[ \t\n\r]+/ R_RESERVED = /\A[\{\}\[\],:]/ R_NUMBER = /\A-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][-+]?\d+)?/ R_STRING = /\A"(?:\\["\\\/bfnrt]|\\u[\dA-Za-z]{4}|[^\\"])*"/ R_FALSE = /\Afalse/ R_NULL = /\Anull/ R_TRUE = /\Atrue/ def initialize(obj) src = obj.is_a?(IO) ? obj.read : obj.to_s @s = StringScanner.new(src) end def scan piece = nil until @s.eos? if (piece = @s.scan R_SPACE) yield :SPACE, piece elsif (piece = @s.scan R_RESERVED) yield piece, piece elsif (piece = @s.scan R_NUMBER) yield :NUMBER, piece.to_f elsif (piece = @s.scan R_STRING) yield :STRING, piece elsif @s.scan R_FALSE yield :FALSE, false elsif @s.scan R_NULL yield :NULL, nil elsif @s.scan R_TRUE yield :TRUE, true else raise RuntimeError, 'must not happen' end end yield false, '$' end def parse yyparse self, :scan end
Examplesはパースできた。
細かい単位(CRとかLFとか)のパースを、パーサにやらせるのがいいのか、正規表現でやるのがいいのか、よくわからないなぁ…