Perl の正規表現でマッチした文字列自体を取得する今昔

  • 18
    Like
  • 0
    Comment
More than 1 year has passed since last update.

伝統的な方法

マッチ全体をキャプチャのカッコでくくる方法です。

# $body から a か A で始まる単語を取り出して $match に入れる
# \b は単語境界を表すゼロ幅マッチ
my $body = "This is apple.";

$body =~ /(\b[Aa]\w+)/;
my $match = $1;
# または my ($match) = $body =~ /(\b[Aa]\w+)/;

カッコによる正規表現キャプチャを書くのが手間ではありますが、伝統的で多くのプログラマーにとっておなじみの方法です。

${^MATCH} 変数による方法

Perl 5.10 以降には ${^MATCH} という変数があって、m//p 修飾子とともに使うことでマッチ全体を ${^MATCH} に入れることが出来ます。

use v5.10;
my $body = "This is apple.";
$body =~ /\b[Aa]\w+/p; # /p 修飾子
my $match = ${^MATCH};

その他にも ${^PREMATCH}${^POSTMATCH} というものもあります。マッチ対象文字列の中で、マッチ全体の左側にあるのが ${^PREMATCH}、右側にあるのが ${^POSTMATCH} です。

Perl 5.20 以降は /p 修飾子が無くても ${^MATCH} などに自動的に入ってくれるようになりました。

[付記] $& による方法

実は、いにしえの Perl から、マッチ全体を表す $& という変数があったのですが、perl の実装上の問題から、一度でもコードの中で $& を書くとプログラム全体の正規表現の性能がガタ落ちになるという致命的な問題がありました。

つまり以前から ${^MATCH} と同様のアイデアはあったわけですが、実装上の問題から使用が避けられていたのです。

${^PREMATCH} == $`

${^MATCH} == $&

${^POSTMATCH} == $'

この事実は広く知られることとなり、$& は忌避されるようになりました。また、ロードするモジュールにもこれがあってもいけないので、それを探す高度なデバッグテクニックなども開発されることとなりました。

そして Perl 5.10 で /p 修飾子が出てくるわけですが、Perl 5.16 で $& などの性能向上が図られることとなり、Perl 5.20 ではこの問題が完全に解決され、$& などを使うことによる性能低下問題はなくなりました。

また Perl 5.20 以降は /p 修飾子は互換性担保のために指定しても無視される修飾子となり、それが指定されていてもされていなくても ${^MATCH} は定義されているし、また$&${^MATCH} は完全に同等になりました。

とはいえ、チーム内で合意が取れているのでなければ $& などの変数の使用は現状は避けておいたほうが無難です(もしくは use v5.20 指定をするなど)。

詳細は最新バージョンの perl より perldoc perlre を参照ください。