« Four on Sixで悩む | トップページ | 「宝箱」で悩む »

2010年9月 9日 (木)

perlのパターンマッチングで悩む

perlのパターンマッチングがおかしな動きをする。これはバグなんじゃないかと思うんだが、Known Issueにも上がっていないようだしなぁ。

どういう話かというと、perlの正規表現でパターンマッチング検索を行ってそのヒット結果を$1とか$2とかの特殊変数でアクセスできるのだが、ヒットしなかった場合にも前回のヒット結果が残ってしまっている、という。

DB<1> $s='13:46 1:46pm 01:46pm pm1:46'
DB<2> $s=~/([012][0-9]:[0-5][0-9]pm)/;print $1
01:46pm

上記では「13:46 1:46pm 01:46pm pm1:46」という文字列から「[012][0-9]:[0-5][0-9][ap]m」というパターンを探してもらいたい、ということを試行している。この要求は厳密で、24時制ではなくて後ろにamまたはpmを付けた12時制で、1時ではなく01時と表記したものだけを拾うということを意図している。カギ括弧でくくられた文字はその位置にそれらの文字だけが許されることを示している。この試行は成功している。

ところが、この直後にパターンマッチングに失敗する例を持ってくるとどうなるか。

DB<3> $s=~/([012][0-9]:[0-5][0-9]pm)/;print $1;$s=~/(abc)/;print $1 01:46pm01:46pm

同じ文字列の中から「abc」を探せという2回目のパターンマッチングには失敗しているのに、あたかも成功したかのように$1には前回のマッチング結果が残っているので、01:46pmというのが2回表示されてしまう。

これを回避するにはパターンマッチングに成功したかどうかを毎回調べないといけない。

DB<4> $s=~/([012][0-9]:[0-5][0-9]pm)/;print $1;if ($s=~/(abc)/) {print $1;} 01:46pm

こうやれば確かにうまく行くのだが、これはめんどくさいし、こんなふうに出来ないこともある。2回目のマッチングを行う前に$1をクリアできればいいのだが、

DB<5> $s=~/([012][0-9]:[0-5][0-9]pm)/;print $1;$1='';$s=~/(abc)/;print $1 01:46pmModification of a read-only value attempted at (eval 23)[C:/Perl/lib/perl 5db.pl:638] line 2.

特殊変数$1はreadOnlyだから変更できないよ、と怒られてしまう。

ふむ、じゃぁ成功するけれどもnulを返すマッチングをやらせればいいのかな?

DB<6> $s=~/([012][0-9]:[0-5][0-9]pm)/;print $1;$s=~/()/;$s=~/(abc)/;print $1 01:46pm

うん、これでうまく行くみたいだな。

|

« Four on Sixで悩む | トップページ | 「宝箱」で悩む »

プログラミング」カテゴリの記事

コメント

「perl $1 リセット」で検索してここへ来ました。
私もまさに同じことが気になりました。
解決策を示していただいて大変助かります。
私のプログラムも正常に動くようになりました。
ありがとうございます。

投稿: d_kawakawa | 2015年4月29日 (水) 20時14分

コメントを書く



(ウェブ上には掲載しません)




トラックバック


この記事へのトラックバック一覧です: perlのパターンマッチングで悩む:

« Four on Sixで悩む | トップページ | 「宝箱」で悩む »