http://cvs.m17n.org/~akr/diary/d2004_03.html#a2004_03_26_1
そうか、MatchData のメソッドにマップする案は既に出てたんですね。
ちなみに「$ 変数ステ」の流れに思いきり逆行して $~name てのはどうでしょうか。 だめですね、はい。
さて、「Ruby 的でない」だけではわからんと言われたので どこが Ruby 的でないと思うか説明します。 Ruby 的でないと思ったのは、 「正規表現をクロージャと考えれば」というところです。 現在 Ruby でクロージャを作るにはブロックを使うか、 メソッドやクラスを定義するか eval するしかありません。 つまり eval 以外は「{....}」か「予約語〜end」です。 正規表現の文法はこのどちらでもないので クロージャ (を作る文法だ) とは認めたくありません。 また eval に似せるなら dynamic scope でないといけません。
だから逆に言うえば「{....}」か「予約語〜end」ならクロージャでもいいです。 ただし %r{....} なんてのは嘘くさいので嫌です。
またそこは我慢するとしても、 その場合は /regexp/ の「/」と「/」の間が文法的なスコープに なるのではないでしょうか。例えば /xxx(?<a=>....)xxx/ は、
lambda { ....; a = xxx; .... }
であって、Ruby ルールでは a は外からは見えないはずです。 もっとも
a = nil re = lambda { ....; a = xxx; .... } p a
であれば納得できますが、この場合、 a = nil は正規表現よりも前になければいけないと思います。 つまり以下のように書くのなら納得できます。
# パターン1 a = nil if /xxx(?<a=>....)xxx/ =~ str p a end # パターン2 a = nil re = /xxx(?<a=>....)xxx/ .... if re =~ str p a end
一方、yacc のように部分パターンごとに アクションが指定できるというのはアリだと感じます。 アクションブロックの文法がブロックに似ていれば違和感を感じません。 例えば
/xxx(??.....){|name| p name }xxxx/ =~ str
とか……。
あ、でもこの場合はそもそも名前付きとは言えませんね。 しかもブロック内なので代入してもブロックローカル。 ブロックが複数あるときに情報を渡すのがめんどくさい。 バックトラックしたらどうなるのか混乱する。 などなど、いろいろな罠がありそうです。
あああああ! そうか! 正規表現一つで済まそうとするからいけないんだ! 正規表現パターンとアクションを組にできるようにして、 それを合成して作ればいい。
pat1 = /xxx/ {|tok| p str } pat2 = /yyy/ {|tok| p str } re = /aaa#{pat1}aaa#{pat2}aaa/
awk だな。awk すぎる。#{...} を使って直接埋め込めばテンポラリ変数も不要か。
re = /aaa#{ /xxx/ {|str| p str } }aaa#{ /yyy/ {|str| p str } }aaa/
むむ……意外といけそうな気がしてきた。
うーん。 でも、こういうアクションみたいのは共有して嬉しいことはなさそうだから、 ブロックは正規表現にではなくマッチする場所に所属するべきか。
/re/ { .... } がパターンとブロックの組を新しく作って返せばいいのかな。 ついでに Regexp#on_match を作って同様の操作ができれば ブロックだけオーバーライドできる。
WikiName = /([A-Z][a-z0-9]+){2,}/ def compile(src) syntax = / #{ WikiName.on_match {|str| .... } } | #{ URI.regexp(%w(http ftp)).on_match {|str| .... } } | #{ /[<>&"]/ {|c| escape_html(c) } } /x src.gsub(syntax) {....} # ここで破綻 end
だめだ、使えない。 このセンはあきらめよう。
(04:29)
Copyright (c) 2002-2007 青木峰郎 / Minero Aoki. All rights reserved.