構文解析(4)
意外と引っ張るなこのネタ.
http://ja.doukaku.org/51/に挑戦してみる.
最初はparseだけでなんとかしようとして,気が狂いそうになったが,こっそりrubyの回答を見て,scanがあればいいのだと知る.
module Parse def scan( str, target=:target) r = [] pos = 0 while pos<str.size m_type, m_len, result = _parse( target, pos, 0, str) if m_type # 常にrに集めさせて、検索終了後にr.each{|x| yield(x)}のほうがいい? # それだと、yield内でパーサの内部情報にアクセスできないので、とりあえず現状維持 if block_given? yield(result) else r << result end end pos += (m_len<=0)? 1: m_len end return (block_given?)? str: r end end
include Parse str = "aaa abc-hidden.png>hoge-big.jpeg" \ "---foo-hidden-small.gif|^_^a.bmp" \ "--hiddena-hoge.png<=not hidden~~" \ "--small.jpg<=not small(^_^)" \ "normal-small-big.hoge" sel :str_p => /\A[A-Za-z]+/ #rep(:str_p => ['A'..'Z','a'..'z']) {|v| v.join} seq :body => [:str_p, opt('-hidden'), opt('-small','-big'), '.', :str_p] scan(str, :body) {|n,h,s,period,e| s = (s.empty?)? 'normal': s[0][1..-1] h = (!h.empty?)? 'True': 'False' puts "name:'#{n}', ext:'#{e}', size: #{s}, hidden: #{h}" }
規則Aを満たす文字列が出るまでスキップするfind(A)を作れば,parse(rep0(find(A)))でscan(A)と等価な処理が,他と統一的な方法で記述できる.
そうすれば.find相当(scanがfind_allとして)も簡単に書けるな.