Perl

正規表現で先読み、後読み(ルックアラウンドアサーション)を使う

いつも忘れる正規表現の先読みと後読み(ルックアラウンドアサーション)のメモです。たぶん、ど忘れとかじゃなくて単にマスターできてないだけだと思います。

ルックアラウンドアサーションはパターンの周りを調べる「幅0のアサーション(zero-width assertion)」です。幅0のアサーションは、それ自体が一つも文字を消費しない(幅がない)もので、文字列や行の始まりを表す(^)や末尾の($)、選択肢の(|)とか、量指定子の(?, *, +)とか、が該当します。詳しい解説はプログラミングPerlの「5章 正規表現」を読んでいただくといいかと思います。

肯定先読みアサーション (?=PATTERN)
positive lookahead

現在の文字列より先の部分(すぐ後ろ)にPATTERNが現れていることを確認します。

my $str = 'あ い い い い い い い い う え お';
$str =~ s/b(.+)s(?=1)b//g;
print $str;
> あ い う え お

先読みアサーションを使用しない場合、ループで回す必要があります。先読みアサーションを使うと1片のコードで済みます。

my $str = 'あ い い い い い い い い う え お';
$str =~ s/b(.+)s1b/$1/g;
print $str;
> あ い い い い う え お
# ループで回す
$str =~ s/b(.+)s1b/$1/g while $str =~ /b(.+)s1b/;

否定先読みアサーション (?!PATTERN)
negative lookahead

現在の文字列より先の部分(すぐ後ろ)にPATTERNが現れないことを確認します。

print "content-type: text/plain; charset=utf8\n\n";

my $str = '<p>Daryl Hall & John Oates</p>';
$str =~ s/&(?!amp;)/&amp;/g;
print $str;
> <p>Daryl Hall &amp; John Oates</p>

肯定後読みアサーション (?<=PATTERN)
positive lookbehind

現在の文字列より前の部分(直前)にPATTERNが現れていることを確認します。

my $str = 'お父さん、お母さん';
$str =~ s/(?<=母)さん/様/g;
print $str;
お父さん、お母様

否定後読みアサーション (?<!PATTERN)
negative lookbehind

現在の文字列より前の部分(直前)にPATTERNが現れてないことを確認します。

my $str = 'お父さん、お母さん、お兄さん、お姉さん';
$str =~ s/(?<!父)さん/様/g;
print $str;
お父さん、お母様、お兄様、お姉様