perlre

Perl 5 以降で使われる正規表現(いわゆる perlre)は,標準的な正規表現とくらべて拡張されています。昔むか〜し(Perl 4 を使っていた頃)は,可搬性が低くなるので個人的に拡張正規表現は使っていなかったのですが,今は便利なだけではなく可読性が高まるので躊躇せず使っています。

指定回数マッチの {数字}

標準正規表現

'12345' =~ m/^\d\d\d\d\d$/

と書くところ,

'12345' =~ m/^\d{5}$/

のように書けます。\d{3,5} と書くと,3回〜5回の最長マッチ,\d{,5} と書くと5回以下のマッチ,\d{3,} と書くと3回以上の最長マッチを行います。この記法は可読性が高くなるのでよく使います。

あと,(後述しますが)基本的に正規表現コンパイルは変数の interpolation 後に行われるので,

my $c = 3;
if ('doooooon' =~ m/o{$c}/) { ... }

みたく書けます。まぁ使いませんけど。

最短マッチの ?

通常,正規表現では出来る限り最長なマッチングを行います。

my ($tag) = ($html =~ m'(<.+>)');

タグをとりだそうと上記のようなことをやっていや〜んなことになったことがあるかたも多いかと思います。
こんなとき,「?」をリピータの末尾につけると最短マッチングしてくれます。

my ($tag) = ($html =~ m'(<.+?>)');

でハッピー。

文字クラス

Perl 独自というわけではないですが,

  • \w = [_0-9A-Za-z]
  • \W = [^_0-9A-Za-z]
  • \s = [ \t\r\n]
  • \S = [^ \t\r\n]
  • \d = [0-9]
  • \D = [^0-9]

とか。[:word:] とか [:digit:] とかも書けますがあまり使わないです(でも [:alpha:] はうれしいかも?)。

で,use utf8 だと

use utf8;
print "matched\n"
  if ('0' =~ m/\d/);

のように,ワイド文字でもマッチします。うれしいような悲しいような(C でもロケールによっては isalpha で全角英字がマッチしたりしますね)。

正規表現記号を無視する \Q 〜 \E

今日これを発見してうれしかったのです(なにげに今までの話は前座)。

print "matched\n"
  if ('h+e+l+l+o' =~ m/\Q+l+\E/);

このように \Q と \E で囲まれたエリアでは,正規表現で使う表記が「文字そのもの」になります。egrep に対する fgrep のような。

これの何がうれしいかというと,

my $word = '[tag]';

print "matched\n"
  if ('test' =~ m/$word/);

文字列の [tag] という表記を探そうとして上のように書くと,「test」でもマッチしてしまうんです。というのは,以前も書きましたが変数の interpolation 後に正規表現コンパイルするので,上記の例では「t か a か g か」という意味になってしまいます。こんなときに \Q 〜 \E を使うと,

my $word = '[tag]';

print "matched\n"
  if ('test' =~ m/\Q${word}\E/);

ちゃんとマッチしません。

普通はこんなコーディングやらないとは思いますが,ユーザからの入力で何かを走査する時,

foreach my $name (@names) {
  if ($name =~ m/^${input}$/) {
    ...
  }
}

ってやってると「.*」とか入力されてどぼーんになりますが(SQL で「'or'1'='1」って入力されるような感じ),こんなときも \Q を使うと回避できます。