綾小路龍之介の素人思考

[perl] /m 修飾子の有無により正規表現 "^" や "$" の意味が変化

perl は文字列が複数行でないことを仮定してマッチングを行う。これを解除して、文字列が複数行であることを伝える修飾子が/m修飾子である。/m 修飾子の有無によって意味の変わる正規表現には "^" や "$" がある。

/m 修飾子の有無による正規表現の意味の違いは以下のように定義されている。

/m 修飾子の有無による正規表現の意味の違い
/m 修飾子無し/m 修飾子有り
\A文字列の開始文字列の開始
\Z文字列の終端または文字列の終端の改行前文字列の終端または文字列の終端の改行前
\z文字列の終端文字列の終端
^文字列の開始行の先頭
$文字列の終端または文字列の終端の改行前文字列の終端または行の終端の改行前

さまざまな文字列のパターンに対して、文字列中の要素(「文字列の開始」など)位置を示すオフセットを書き出すと以下のようになる。

文字列中の要素(「文字列の開始」など)位置
文字列
開始終端の改行前終端先頭終端の改行前終端
""0-00-0
"\n"001001
"aa"0-20-2
"aa\n"023023
"aa\nbb"0-50,323,5
"aa\nbb\n"0560,32,53,6

上に挙げた文字列に対して m//g と m//mg を行い、マッチングの終了した位置を先頭から順に pos 関数で書き出した結果が以下である。

マッチングの終了した位置
m/\A/m/\Z/m/\z/m/^/m/$/
/g/mg/g/mg/g/mg/g/mg/g/mg
""0000000000
"\n"000,10,111000,10,1
"aa"0022220022
"aa\n"002,32,333002,32,3
"aa\nbb"00555500,352,5
"aa\nbb\n"005,65,66600,35,62,5,6

上のテーブルは下のスクリプトを用いて作成した。

#!/usr/bin/perl -w
use strict;
use warnings;

my @regex = qw(\A \Z \z ^ $);

print "<table>\n";

print "<tr><td></td>";
foreach (@regex) {
        print qq(<td colspan="2">m/$_/</td>);
}
print "</tr>\n";

print "<tr><td></td>";
foreach (@regex) {
        foreach my $mod (qw(g mg)) {
                print qq(<td>/$mod</td>);
        }
}
print "</tr>\n";

foreach my $src ("", "\n", "aa", "aa\n", "aa\nbb", "aa\nbb\n") {
        my $src0 = $src;
        $src0 =~ s/\n/\\n/g;
        print qq(<tr><td>"$src0"</td>);
        foreach my $regex (@regex) {
                print "<td>";
                while ($src =~ m/($regex)/g) {
                        print pos $src, ',';
                }
                print "\x08</td>";
                print "<td>";
                while ($src =~ m/($regex)/mg) {
                        print pos $src, ',';
                }
                print "\x08</td>";
        }
        print "</tr>\n";
}
print "</table>\n";

具体的に置換を行った結果が以下。

置換結果
s/\A/|/s/\Z/|/s/\z/|/s/^/|/s/$/|/
/g/mg/g/mg/g/mg/g/mg/g/mg
"""|""|""|""|""|""|""|""|""|""|"
"\n""|\n""|\n""|\n|""|\n|""\n|""\n|""|\n""|\n""|\n|""|\n|"
"aa""|aa""|aa""aa|""aa|""aa|""aa|""|aa""|aa""aa|""aa|"
"aa\n""|aa\n""|aa\n""aa|\n|""aa|\n|""aa\n|""aa\n|""|aa\n""|aa\n""aa|\n|""aa|\n|"
"aa\nbb""|aa\nbb""|aa\nbb""aa\nbb|""aa\nbb|""aa\nbb|""aa\nbb|""|aa\nbb""|aa\n|bb""aa\nbb|""aa|\nbb|"
"aa\nbb\n""|aa\nbb\n""|aa\nbb\n""aa\nbb|\n|""aa\nbb|\n|""aa\nbb\n|""aa\nbb\n|""|aa\nbb\n""|aa\n|bb\n""aa\nbb|\n|""aa|\nbb|\n|"

上のテーブルは下のスクリプトを用いて作成した。

#!/usr/bin/perl -w
use strict;
use warnings;

my @regex = qw(\A \Z \z ^ $);

print "<table>\n";

print "<tr><td></td>";
foreach (@regex) {
        print qq(<td colspan="2">s/$_/|/</td>);
}
print "</tr>\n";

print "<tr><td></td>";
foreach (@regex) {
        foreach my $mod (qw(g mg)) {
                print qq(<td>/$mod</td>);
        }
}
print "</tr>\n";

foreach my $src ("", "\n", "aa", "aa\n", "aa\nbb", "aa\nbb\n") {
        my $src0 = $src;
        $src0 =~ s/\n/\\n/g;
        print qq(<tr><td>"$src0"</td>);
        foreach my $regex (@regex) {
                my $dst = $src;
                $dst =~ s/($regex)/|/g;
                $dst =~ s/\n/\\n/g;
                print qq(<td>"$dst"</td>);
                $dst = $src;
                $dst =~ s/($regex)/|/mg;
                $dst =~ s/\n/\\n/g;
                print qq(<td>"$dst"</td>);
        }
        print "</tr>\n";
}
print "</table>\n";

リファレンス

  1. perlre - Perl 正規表現 【perldoc.jp】
  2. pos 【perldoc.jp】
  3. perlretut - Perl の正規表現のチュートリアル 【perldoc.jp】

ソーシャルブックマーク

  1. はてなブックマーク
  2. Google Bookmarks
  3. del.icio.us

ChangeLog

  1. Posted: 2010-02-26T07:56:23+09:00
  2. Modified: 2010-02-26T07:56:23+09:00
  3. Generated: 2017-04-10T23:09:26+09:00