<パターンマッチング>

おことわり

この項目は、いつにも増していい加減であることを最初にお断りしておく。

で、パターンマッチングって?

「ある文字列内を検索して、指定したパターンに一致する所があるかどうかを調べる」こと。
ただ単に調べるだけでなく、一致した場所を別の物に置き換えたりすることもできる。

手段

パターンマッチの演算子を使う方法と、grep関数を使う方法がある。
ここでは前者だけを扱う。

パターンマッチ演算子

3つがある。 マッチ演算子 m// は、ただ単に対象に対しパターン検索を行い、マッチした場合に真を返す。
置換演算子 s/// は、 s/[パターン]/[置換文字列]/ のように指定して、[パターン]にマッチした部分を[置換文字列]で置き換える。
変換演算子 tr/// は置換演算子と主旨は似ているが方向性が若干異なる。 置換演算子が「ある言葉を別の言葉に置き換える(例:"赤"を"青"に置換)」というような目的で使われるのに対し、 変換演算子は「ある表現を別の表現に置き換える(例:アルファベット"大文字"を"小文字"に変換)」為に使われる。

対象

いずれの演算子も、特に指定しなければパターンマッチの対象は変数$_となる。
対象を別に指定するには、マッチングしたい変数の後ろに=~に続けてマッチング演算子を置く。
$is = $there =~ m/restaurant/;

これで、変数$thereが文字列'restaurant'を含むか否かが変数$isの中に代入される。

$isnt = $there !~ m/restaurant/;

上のように=~の代わりに!~を使うと、パターンマッチ演算子の返す結果が論理反転(真偽反転)する。 よって、$isntの中には$thereが'restraunt'を含んでいないか否かが代入される。

より柔軟なパターン検索の為に
パターンを単純に指定したのでは、1つの演算子につき1つのパターンしか検索できず、これでは効率が悪すぎる。 そこで、1つの演算子で複数のパターンを検索できるようにパターンを多様化させる記法が存在する。 これが正規表現(Regular Expression)である。
以下で簡単な例を挙げる。
(注:tr演算子では正規表現は使えない)

reg.pl :

#!/usr/bin/perl
$example='stick stuck struck stmach';
$str1=$str2=$str3=$str4=$example;
$str1 =~ s/st(i|ru)ck/hit/g;
$str2 =~ s/st.ck/hit/g;
$str3 =~ s/st.+ck/hit/g;
$str4 =~ s/st.+?ck/hit/g;
print "$str1\n$str2\n$str3\n$str4\n";

結果:
$ ./reg.pl
hit stuck hit stmach
hit hit struck stmach
hit stmach
hit hit hit stmach

パターンマッチ演算子の末尾に"g"(global)を付けると"グローバルマッチング"を行う。 通常のマッチングは、文字列の先頭から順次検索していきマッチした時点で検索を止めるが、 グローバルマッチの場合、一致するもの全てを捜し出す。

さて、この例では、分かり易くするために m// ではなく s/// を用いた。
同じ文字列のコピー4つに対しそれぞれ異なる条件でパターンマッチングを行い、一致した箇所を"hit"で置き換える。 わざわざコピーを取る理由は、同じ文字列に対し連続でパターンマッチングをすると検索開始位置がずれてしまうからである。

最初のパターンマッチング(4行目)は"st(i|ru)ck"。
これは日常でも使われる書き方かもしれない。"|"は直前と直後のパターンの論理和を意味する。よって、このパターンは stとckの間がiかruである部分、 すなわちstickまたはstruckのみにマッチする。結果を見ると実際にそうなっている。

2番めのパターンは"st.ck"。パターン中の".(ドット)"は、"任意の1文字"を表わす。 つまり、stとckの間に何か1文字入っている部分にマッチする。 今回はstickおよびstuckであった。

さて、3番めであるが、今回のパターンは"st.+ck"である。 "."は任意の一文字で、それに続く"+"は「直前のパターンの1回以上の繰り返し」を意味する。 従ってパターンは「stとckの間に任意の文字が1文字以上」を表わす。 これを踏まえると、結果は"hit hit hit stmach"となっていて欲しい所であるが、そうはなっていない。 実は、Perlのパターンマッチはデフォルトで最長マッチを行うようになっている。 最長マッチとは、見付けたパターンのうち最も長い物にマッチングさせることである。こう書いてもよく分からないと思うが、
"stick stuck struck stmach"
と言う風に、"stick stuck struck"をひとまとまりに考えてしまう、ということである。

これを踏まえて、4番めのパターンには、最短マッチを行わせる為、"+"の直後に"?"を付け加えている。 "+"のような、"あるパターンの繰り返し"を表わすものを量化子と言うが、量化子の直後に"?"をつけることで、 その量化子に対し最短マッチを行うように指定できる。これにより、4番めの出力はちゃんと "hit hit hit stmach"となる。

ただし、"?"については注意が必要である。"?"はそれ自体量化子であり、「0回または1回の繰り返し」を表わす。

なお、今回用いたような記号(. や + など)自体をパターンに使いたい場合は、その直前に"\"(バックスラッシュ)を置くことでエスケープすることができる。

!推奨!
正規表現およびパターンマッチングについては、書籍ならびにより情報量・信頼性の高いウェブサイトを参照することを強くお薦めします。

accend->Perl->labnote->index page