13.6 正規表現

少し空いてしまった。前回は文字列のところ。正規表現から。

リテラル

は #/regex/ 。覚えやすい。#/../iでcase-insensitive。ひょっとして gとか使える? と思ったけどダメだった。
正規表現自体は殆どperl5。

マッチング

rxmatchを使ってマッチング。けど、実はrxmatchを使わなくても略記法があって、直接オブジェクトを手続きチックに呼び出す (#/regex/ string) ことでもおK。直感的。
マッチング結果は regmatchオブジェクトで、マッチ文字列を取り出す手続きrxmatch-{substring|before|after}があるのだけれど、上と同様に略記法があって、regmatchを手続きチックに書ける。

gosh> (let ((match (#/foo/ "bar foo alt") ))
	(map match '(before 0 after)))
("bar " "foo" " alt")

な〜るほど。非マッチの時の事を考えると rxmatch-*が #fを引数として認めているので楽かも*1
グルーピングした場合、regmatchの後ろにインデックスを与える事で、各マッチを取得することができる。

gosh> (let ((match (#/(\d{2}):(\d{2}):(\d{2})/ "10:22:34") ))
	(map match (iota (rxmatch-num-matches match))))
("10:22:34" "10" "22" "34")

あれ、 num-matchesってば一つ多い? と、そうか、全体マッチも含まれてしまうのか。なるほど。
pythonとかrubyっぽく同時に変数に束縛する方法無いかな、、と思ったらそのものズバリの rxmatch-letというのがあった*2

gosh> (rxmatch-let (#/(\d{2}):(\d{2}):(\d{2})/ "10:22:34")
		   (whole hh mm ss)
		   `(,hh ,mm ,ss))
("10" "22" "34")

余談だけれど、gaucheリファレンスの例も時刻表示だったのがちょっとうれしかった*3

適用可能なオブジェクト

regexとか matchとか手続きチックに呼び出してるの凄いなあと思って感動していたら実はまた魔法ではなかったので更に感動した。
carが手続きとか総称関数とかでないときに

 (a b) => (object-apply  a b)

のように解釈してくれるので、上記メソッドを定義してやると

gosh> (define-method object-apply ((i1 <integer>) (i2 <integer>))
	(* i1 i2))
#<generic object-apply (7)>
gosh> (10 20)
200

のわー、なんというかすさまじい。

*1:この辺りは僕がまだあまりlisp(というか関数言語)慣れしていないせいかと思う。Maybeチックに書けばよいのだよね

*2:プログラミング gaucheではrxmatch-caseが紹介されていた。マッチ失敗も扱えるのであっちの方が便利

*3:まあ、普通これがパっと浮かぶんだろうけど