§7.2 もっと正規表現


作成日:2001/08/25(土)

前節では、正規表現の第1歩として1文字にマッチさせるためのパターンの作り方を見てきました。 この節では、複数の文字にマッチさせるための方法をいくつか紹介します。

複数の文字にマッチ

といっても、何も大変なことはありません。 複数の文字にマッチさせるには、それらの文字列を正規表現の中で並べればいいのです。 例えば/can/は、cの次にaが来て、その次にnが来る文字列にマッチします。

 You can do it!
 candy
 candle

また/<br>/はHTMLの改行タグにマッチします。 前節で紹介した文字クラスを組み合わせて/<h\d>/とすれば見出しタグにマッチし、/<h\w>/とすれば<hr>にもマッチします。 では、

 I can't help eating candy!

という文に対しては、どちらのcanにマッチするのでしょうか? Perlの正規表現ではなるべく左からマッチさせていくので、この場合は"I can't"のcanにマッチします。

次に、"can"か"Can"か"CAN"のどれかにマッチさせたい場合を考えましょう。 正規表現の中の複数の文字列のうちのどれかにマッチさせるには|(縦棒)を使います。 これを使って"can"、"Can"、"CAN"のどれかにマッチさせるには、

 /can|Can|CAN/

とします。

量指定子

"soon"や"moon"など、"oo"と繰り返すような文字列にマッチさせるには「量指定子」を使います。 量指定子にはいろいろな物があるので一つ一つ見ていきましょう。

*(アスタリスク)
 *(アスタリスク)は、直前の文字及び文字クラスが0個以上続くような文字列にマッチします。 例えば、

 @words = qw(soon moon noon orange water);
 foreach (@words) {
   if(/o*/){
     print "$_ ";
   }
 }

とすると、"soon"や"moon"等にマッチします。 しかし、上のスクリプトを実行すると"water"にもマッチしてしまいます。 *は、直前の文字及び文字クラスが0個以上続くような物にマッチするので、文字が全くない場合、つまり空文字列にもマッチしてしまいます。 マッチングのときには、文字列の前後や文字の間に空文字列があると解釈されるので"water"にもマッチしてしまうのです。

+(プラス)
 +(プラス)は直前の文字及び文字クラスが1個以上続くようなものにマッチします。 上のスクリプトを書き換えて、

 @words = qw(soon moon noon orange water);
 foreach (@words) {
   if(/o+/){ #*を+に変更
     print "$_ ";
   }
 }

としてみましょう。 今度はちゃんと"water"にはマッチしませんね。 

?(疑問符)
 ?(疑問符)は、直前の文字及び文字クラスが0個または1個続くような文字列にマッチします。 ですから、

 @words = qw(soon moon noon orange water);
 foreach (@words) {
   if(/o?/){
     print "$_ ";
   }
 }

を実行すると、@wordsの中の全ての文字列にマッチします。

もっと細かく
 *、+、?と3種類の量指定子を紹介してきましたが、これらでは「ちょうど2回」とか「3回以上10回以下」といったような細かい指定は出来ません。 そのような芸当をしてくれるのは{m}、{m,}、{m,n}等の指定子です。 {m}はちょうどm回繰り返し出現するパターンにマッチします。 例えば「けろけろ」にマッチさせるには/(けろ){2}/のように、「けろ」を( )で囲みます。 もし( )で囲むのを忘れてしまって/けろ{2}/とすると「けろろ」にマッチします。
 {m,n}指定子は、直前の文字及び文字クラスがm回以上n回以下繰り返し出現するパターンにマッチします。 例えば/(けろ){3,5}/は「けろけろけろ」、「けろけろけろけろ」、「けろけろけろけろけろ」にマッチします。 またm回以上繰り返し出現するパターンにマッチさせるには/(けろ){m,}/のように、2番目の数字を省略します。 さらに、n回以下繰り返し出現するパターンにマッチさせるには/(けろ){0,n}/とします。 /(けろ){,n}/ではないので注意してください。
 次の表は、*、+、?をそれぞれ{m,n}指定子を使って表した物です。

指定子 {m,n}で書くと…
* {0,}
+ {1,}
? {0,1}

最長マッチと最短マッチ
 さて、

 I can't help loving can.
 #え? あ、そう? てれるな〜。

という文の中で"I can"という文字列にマッチさせようとして、

 /.*can/

とすると、実際には文末の"can"にマッチしてしまいます。 これは量指定子が、対象の文字列が複数ある場合、最も長い物にマッチしようとする「最長マッチ」の機能を持っているからです。 最も短い範囲でマッチさせるには、使われている量指定子の直後に?をつけます。 上の例の場合、ちゃんと"I can"にマッチさせるには、*のあとに?をつけて、

 /.*?can/

とします。
 量指定子を使わない正規表現では最短マッチを行います。 この辺は混同しないように注意が必要です。

後方参照

例えば、

 <h1>正規表現</h1>

というような、対になったHTML文にマッチさせるにはどうすればいいでしょうか? 今まで見てきたことを使って、

 <.+>.+</.+>

とすればうまく行くでしょうか? でもこれだと、

 <h1>正規表現</h2>

にもマッチしてしまいます。 このように、1度マッチしたパターンを憶えておいて、あとでもう1度マッチさせたいというようなときに使えるのが「後方参照」という機能です。 これを使って上の正規表現を書きかえると、

 <(.+)>.+</\1>

のようになります。 まず、記憶させたいパターンを( )で囲みます。 そして、もう1度マッチさせたい場所で、\整数という形で呼び出します。 この整数の値は1から始まり、( )で囲まれた正規表現が現れた順番を表しています。 ですから、最初に( )で囲んだ部分は\1によって参照され、次に( )で囲んだ物は\2で参照されるのです。 例えば、

 <h1><i>正規表現</i></h1>

にマッチさせるには、

 <(.+)><(.+)>正規表現</\2></\1>

とします。

位置を指定してマッチさせる

「行頭の"can"」や「行末の"can"」など、文字列が置かれている位置まで指定してマッチさせたい場合には、次のような演算子を使います。

^(キャレット)または\A
 ^(キャレット)または\Aを使うと、行頭の文字列にマッチします。 例えば、/^can/は、"candy"や"candle"にはマッチしますが、"American"にはマッチしません。

$または\Z
 $または\Zは行末の文字列にマッチします。 例えば/can$/は、先ほどの例とは反対に"American"にはマッチしますが、"candy"や"candle"にはマッチしません。

\b
 \bは単語の境界(\wと\Wの間)にマッチします。 例えば、/can\b/は、"American"にはマッチしますが、"candy"や"candle"にはマッチしません。

\B
 \Bは\bとは反対に単語の境界以外にマッチします。 ですから、/can\B/は"candy"や"candle"にはマッチしますが、"American"にはマッチしません。

さて、この章の最初に、「僕は」で始まり「猫が好き。」で終わる文にマッチさせるための正規表現を紹介しました。 それは、

 /^僕は.*猫が好き。$/

というものでした。 ここまで勉強してこられた皆さんには、これがなぜなのかもうおわかりだと思います。 上の正規表現は、「行頭に『僕は』があり、その後に改行文字以外の文字が0個以上続き、行末に『猫が好き。』が来るような文字列」にマッチします。

いかがでしたか? この章の最初にも書きましたが、正規表現はPerlの強力な武器です。 皆さんもいろいろなパターンをつくって実験してみてください。 次の節では正規表現の拡張機能について紹介します。


「§7.1 正規表現」へ 「§7.3 正規表現の拡張機能」へ
ソフトバンク パブリッシング株式会社

Copyright (C) can All Rights Reserved
e-mail:ishiki@mrj.biglobe.ne.jp