正規表現:非欲張り量指定子

今日の勉強は,正規表現の非欲張り量指定子についてです.あまりRubyは関係ありませんが,知っておくと便利ですので,読んでみると良いかもしれませんよ.ただし,ボクがこういう風に理解しただけですので,注意や指摘は甘んじて受けます.


量指定子(+,*,?,{num,num})てのは,基本的に欲張りです.たとえば,"Copyright 2006."という文字列があるとします.この文字列の,"2006"だけを参照したい時,

l = "Copyright 2006."

puts $1 if l =~ /^.*([0-9]+)/

というように正規表現を使用したとすると,後方参照される文字列($1)には何が入るでしょうか?実はこれ,詳説正規表現に載っていた問題なのですが,この場合,"2006"ではなく,"6"だけになります.


何故でしょうか?それは,量指定子"*"が欲張りだから,"."にマッチするものなら少しでも多くマッチさせようとするからです.
まず,"^.*"ですので,とりあえずたくさんマッチすべく,"Copyright 2006."までマッチさせます.しかし"[0-9]+"があるので,"."を捨てて"Copyright 2006"まで戻ります.次に,"[0-9]+"が,「少なくとも一つは俺にも分けてくれYO!」と言ってくるので,"6"だけ渡します.
"+"は「少なくとも一つ以上」なので,"[0-9]+"にマッチするのが"6"だけでも何も問題はありません.なので,後方参照されるのは"6"だけになるのです.


ここで威力を発揮するのが,非欲張り量指定子(+?,*?,??,{num,num}?)です.量指定子の後に"?"を付けただけ.それでは,先ほどの正規表現を少し変更してみましょう.

l = "Copyright 2006."

puts $1 if l =~ /^.*?([0-9]+)/

違いは,"*"が"*?"になっただけです.こうすると,後方参照される文字列には,期待通り"2006"が入ってくれます.それではこのときの正規表現の動きを見てみます.


まず,"^.*?"ですが,非欲張りです.出来るだけマッチしたくないんです.この正規表現だと,「文字列の先頭から何かが複数個あった後,次に数字が来るものにマッチ」します.「文字列の先頭から何かが複数個」の後に,「数字」があるという事が分かっています.という事で,"^.*?"は先頭から数字の直前までのマッチで満足します.

結局,"^.*?"にはCopyright "までがマッチし,"[0-9]+"には"2006"がマッチする事になりました.これが,欲張りと非欲張りです.楽しいでしょ?


今度は,

l = "Copyright 2006."

puts $1 if l =~ /^.*?([0-9]+?)/

としてみます.
このとき,後方参照される文字列には"2"が入ります.さらに,こんなこともしてみます.

l = "Copyright 2006."

puts $1 if l =~ /^.*?([0-9]*?)/

こうすると,"^.*?"も"[0-9]*?"も,出来るだけマッチしたくないので,何にもマッチしません.それは,"*"が0個のマッチも含むからです.先ほどの例だと,"[0-9]+?"が少なくとも一つにマッチしなければならないので,"^.*?"が「仕方なく」"Copyright "までマッチするんですね.面白い.


でもまぁ正直,"2006"にマッチさせたければ

/(\d+)/

で良いよね.