先読みと後読みを理解する
正規表現を学んでいくと出会うのが、
先後読みを使いこなすと、
ここでは、
先後読みはゼロ幅マッチ
正規表現のメタ文字には文字自体にマッチするもののほか、
ゼロ幅マッチは、^、$、\bはゼロ幅マッチです。そして重要なのが、
ゼロ幅マッチはマッチ文字列に入ることがないので、s///で文字列置換の対象に入ることがありません。このことを指して、
先後読みの記法
先読みと後読みにはそれぞれ肯定と否定があり、
| メタ文字 | 名前 | 説明 |
|---|---|---|
| (?=●) | 肯定の先読み | この位置の右側が正規表現●にマッチすることを要請 |
| (?!●) | 否定の先読み | この位置の右側が正規表現●にマッチしないことを要請 |
| (?<=●) | 肯定の後読み | この位置の左側が正規表現●にマッチすることを要請 |
| (?<!●) | 否定の後読み | この位置の左側が正規表現●にマッチしないことを要請 |
まず、 正規表現 この例だと 初学者が先後読みを学んだ際、 前項の しかし、 時間軸で考える場合も、 「後」 先読みや後読みはゼロ幅マッチであると解説しましたが、 図1では このように、 ゼロ幅マッチは位置にマッチしますが、 上記で しかし、 幅のある1文字をキャプチャする例と比較すると、 先後読みを使うか、 前項で否定の先読みの例が登場しましたが、 紙幅の都合上、 筆者は東京在住なのですが、 検索に正規表現を使えるのであれば、 ちなみに、 「東京都」 本項では、 ゼロ幅マッチを一段下げて読む例で表すと、 本稿では、 Perlの正規表現は、 さて、my $intro = "私は牛乳と牛丼が好きです";
$intro =~ s/牛(?=丼)/豚/g;
print "$intro\n"; # => 私は牛乳と豚丼が好きです牛(?=丼)は、牛の右側に丼がある場合、牛にマッチします。丼は先読み(?=丼)によってマッチに必要な条件ですが、丼という文字を消費しません)。そのため、牛となり、牛丼のみ豚丼に置換されます。s/牛丼/豚丼/gでも代用できます。しかし、先や後はマッチカーソルの動き
s/牛(?=丼)/豚/gのサンプルは、牛の後に丼がある場合」牛をマッチ文字列候補に取り込んだけれど、ゼロ幅マッチは一段下げて読む
牛(?=丼)を例として、(?=丼)を下の行に移しています。ゼロ幅マッチが位置にマッチすることと、
隣接する複数のゼロ幅マッチはAND条件
my @data = ("1 Alice", "", "3 Carol", "Dave");
for my $line (@data) {
$line =~ s/^(?!\d)/WARNING:/; ――(1)
print "$line\n";
}^かつ否定の先読み(?!\d)によって数値が右側に存在しない位置に文字列WARNING:を挿入するサンプルです。正規表現がゼロ幅マッチのみで構成されており、1 Alice
WARNING:
3 Carol
WARNING:Dave^(?!\d)は位置に関する2個の条件のAND条件となっており、(?!\d)^と書いても同じ意味です。しかしこの場合は、(?!\d)の右側に書く意義はないでしょう。ただ、s///に収めようとすると、$line =~ s{^(.)}{
my $x = $1; $x =~ /^\d$/ ? "$x" : "WARNING:$x";
}e;$lineが空文字の場合に対応できていません。また、s{●}{■}eの置換文字列を得るためのPerlコード■の中にm//があることが読みやすいかどうかは、否定の先後読みの実践
s/牛(?=丼)/豚/gとs/牛丼/豚丼/gの例で見たとおり、否定の先後読みを日本語の単語境界の代用として使う
\bは日本語文字列に対応していない\b京都\bではうまくいきません否定の後読みで単語マッチを限定する
my @entries = (
"東京都の自宅を出て品川駅へ移動", ――(1)
"品川駅から東海道新幹線に乗車", ――(2)
"東海道新幹線の京都駅で下車",
"京都市右京区へ移動",
);
for my $entry (@entries) {
if ( $entry =~ /(?<!東)京都/ ) { ――(3)
print "$entry\n";
}
}(?<!東)京都によって、否定の先読みで単語マッチを限定する
my @entries = (
"東京都の自宅を出発",
"京都府の旅館に到着",
"京都嵐山を散策", ――(1)
"バスで京都市街を移動",
"京都文化博物館を観覧", ――(2)
);
for my $entry (@entries) {
if ( $entry =~ /(?<!東)京都(?!府)(?!市)/ ) { ――(3)
print "$entry\n";
}
}(?<!東)京都(?!府)(?!市)は、(?<!東)のほか、(?!府)(?!市)によって、(?!府)と(?!市)の関係も把握しやすくなります。
まとめ

