正規表現はがっつく

彼ってがっつくタイプ

とかくがっつく男は嫌われがちですが、正規表現くんはいつもがっつく。わたくしも結構がっつくタイプなので気が合うようです。ただ一旦正規表現くんがそういう性格だとわかってしまえば簡単なのですが、気づくまではぽかーんとなってしまいました。

よくある例としては、

<.*>

という正規表現

<html><head></head></html>

という文字列にかけると、たぶんかかって欲しいであろう <html> ではなく、<html><head></head></html> になっちゃうという例のあれです。なので大抵の正規表現の実装だと、「おまえそんながっつくな」という意味の ? という表現があって…、

<.*?>

という感じにして、<html> にマッチさせます。
実は sed正規表現にはこの ? が無くて、GNU sed にも無くて、みんなしぶしぶ

<[^>]*>

と書いてたりします(ちなみに awk には ? あります嘘でした!)。

たまにそれを忘れる

これくらいだと一つのFAQとして覚えてしまうのですが、色々書いているとふと忘れてしまって、こないだの sed スクリプトでファイル中の一部の表現を抜き出すってのを作った時、早速ぽかーんとなりました。

/###[^#]*###/ {
	:print
	h
	s/\(###[^#]*###\).*$/\1/
	s/^.*\(###[^#]*###\)/\1/p

	g
	s/###[^#]*###//
	t print

	:end
}

この中の、

	s/\(###[^#]*###\).*$/\1/
	s/^.*\(###[^#]*###\)/\1/p

この部分です。この部分はどうしてるかと言いますと、例えば

<strong>###test###</strong>は、###hogehoge###だから###unyounyo###です。

という文から、先に出てくる方の ###test### を抜き出して出力してやろうとしたものです。

始めなんにも考えずに書いた時は、正規表現の順番を逆に

	s/^.*\(###[^#]*###\)/\1/
	s/\(###[^#]*###\).*$/\1/p

こう書いていたのですが、これだと駄目なんですね!一番後ろの ###unyounyo### がひっかかってきてしまいました。お前はお呼びじゃないぞ。

長持ちの秘訣

ここでしばらくぽかーんとした後ぴかーんと来て、正規表現ががっついていることに気がつきました。
s/^.*\(###[^#]*###\)/\1/ という表現は、単に

「先頭から###うんにゃら###まで」

ではなくて

「先頭###うんにゃら###まで、出来るだけ長く!

という表現だったのです!。衝撃!。そりゃあ一番長く取るんだったら、最後のが出てきちゃう!
いやはや正規表現くんのこの性格。かなりがっついていると言えます。さすがです。アブナイです。でも気をつけてお付き合いすれば、つまり、何かの正規表現を頭の中で日本語読み下し文に変換するときは後ろに「出来るだけ長く!」を付けて考えるようにすれば、正規表現くんかなり良い奴といえます。