正規表現の先読みと後読みを使いこなす

Perlにはルックアラウンドアサーション(lookaround assertion)という4つの正規表現拡張があります。肯定の先読み・否定の先読み・肯定の後読み・否定の後読みの4つです。

(?=...) : 肯定の先読み
(?!...) : 否定の先読み
(?<=...): 肯定の後読み
(?<!...): 否定の後読み

これらの使い方を紹介します。

例えば、HTMLのタグとタグの間の空白文字をs///演算子で全て取り除きます。

ルックアラウンドを使わない場合は、

$html =~ s/>\s+</></g;                    # ルックアラウンドを使わない

と書けます。少し読みにくくなるので、Perlベストプラクティスで書きます。

$html =~ s{ > \s+ < }{><}gxms;            # ルックアラウンドを使わない。Perlベストプラクティスの書き方

となります。

ですが、置き換える必要のない山カッコまで置き換えるのはスマートではないですよね?
そこでルックアラウンドを使います。

直前に左山カッコが現れる位置を肯定の後読みでマッチさせて、直後に右山カッコが現れる位置を肯定の先読みでマッチさせる事で、山カッコを置き換えず、空白文字だけを置き換える(ここでは取り除く)対象にできます。

$html =~ s{ (?<= > ) \s+ (?= < ) }{}gxms; # ルックアラウンドを使う

ただ、これではファイル先頭もしくは末尾に空白文字がある場合にそれを取り除く事ができません。
それも取り除くには次のように、先頭および末尾にもマッチする以下のパターンでも良いですが、

$html =~ s{ (?: \A | (?<= > ) ) \s+ (?: (?= < ) | \z ) }{}gxms;

と長くなってしまいます。

否定の後読みおよび否定の先読みと文字クラスの否定を使うと、以下のようにもっとシンプルに表現できます。

$html =~ s{ (?<! [^>] ) \s+ (?! [^<] ) }{}gxms;

これは、

(?<![^>]): 直前に右山カッコ以外の文字は現れない
(?![^<]) : 直後に左山カッコ以外の文字は現れない

という表現になり、つまり、

(?<![^>]): 直前に右山カッコが現れる、もしくは文字が無い
(?![^<]) : 直後に左山カッコが現れる、もしくは文字が無い

という意味になるためです。おもしろいですね!

コメントを残す

メールアドレスが公開されることはありません。