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 |
うん、これでうまく行くみたいだな。
| 固定リンク
「プログラミング」カテゴリの記事
- HTMLのaudioオブジェクトで悩む(2017.07.09)
- JavaScriptで悩む(2017.04.01)
- プログラム言語「Ruby」で悩む(2016.07.03)
- 苗字の漢字で悩む(2015.09.06)
コメント
「perl $1 リセット」で検索してここへ来ました。
私もまさに同じことが気になりました。
解決策を示していただいて大変助かります。
私のプログラムも正常に動くようになりました。
ありがとうございます。
投稿: d_kawakawa | 2015年4月29日 (水) 20時14分