欲張りなマッチと控え目なマッチ(最小量指定子)

繰り返しを扱うメタ文字を使用するパターンの場合、対象の文字列のいくつかの個所のマッチすることがあります。その場合、デフォルトでは最大限にマッチする範囲が多くなる位置でマッチします。これを欲張りなマッチと呼びます。また最小量指定子を追加することで、一番少ない範囲とマッチするように変更することもできます。これを控えめなマッチといいます。ここでは Perl の正規表現で欲張りなマッチと控え目なマッチを行う方法について解説します。

(Last modified: )

欲張りなマッチ

繰り返しを表すメタ文字を使用する場合、パターンが対象の文字列のいくつかの個所にマッチする場合があります。このときデフォルトでは最大限にマッチする範囲が多くなる位置でマッチします。これはメタ文字の +, *, ?, {min,max} のどれを使った場合でも同じです。

例として任意の文字を表すメタ文字 . に対して 1 回以上繰り返しすメタ文字 + を使った場合で考えてみます。

/a.+b/

上記は "a" で始まり任意の文字が連続して続き、 "b" で終わる文字列にマッチします。このパターンを文字列 "00a11b22b33b44" に対して適用すると次の位置でマッチする可能性があります。

00a11b22b33b44
00a11b22b33b44
00a11b22b33b44

この時、デフォルトではマッチする範囲が最大になるようにマッチするため、実際にマッチするのは次の位置になります。

00a11b22b33b44

このように最大の範囲でマッチすることを「欲張りなマッチ」と呼ばれています。

控え目なマッチ(最小量指定子)

マッチする範囲が最小になるようにマッチさせたい場合もあります。このときは各メタ文字のあとに最小量指定子の ? を付けて使用します。例えば + を使用する場合に、メタ文字のあとに最小量指定子の ? を付けて +? と記述します。

+?
*?
??
{min,max}?
{min,}?
{num}?

例として先ほどと同じように任意の文字を表すメタ文字 . に対して 1 回以上繰り返しすメタ文字 +? を使った場合で考えてみます。今回は最小量指定子付きとなっています。

/a.+?b/

上記は "a" で始まり任意の文字が連続して続き "b" で終わる文字列にマッチします。このパターンを文字列 "00a11b22b33b44" に対して適用すると次の位置でマッチする可能性があります。

00a11b22b33b44
00a11b22b33b44
00a11b22b33b44

今回は最小量指定子が付いていますのでマッチする範囲が最小になるようにマッチするため、実際にマッチするのは次の位置になります。

00a11b22b33b44

このように最小の範囲でマッチすることを「控え目なマッチ(又は欲張りでないマッチ)」と呼ばれています。

サンプルコード

それでは簡単なサンプルを作成します。

use strict;
use warnings;
use utf8;
binmode STDIN, ':encoding(cp932)';
binmode STDOUT, ':encoding(cp932)';
binmode STDERR, ':encoding(cp932)';

&check1("aP12P34P56Pa");

sub check1{
  if ($_[0] =~ /P.+P/){
    print $_[0]." は /P.+P/ にマッチします。\n";
    print "マッチした部分は $& です。\n";
  }else{
    print $_[0]." は /P.+P/ にマッチしません。\n";
  }
}

print "----\n";

&check2("aP12P34P56Pa");

sub check2{
  if ($_[0] =~ /P.+?P/){
    print $_[0]." は /P.+?P/ にマッチします。\n";
    print "マッチした部分は $& です。\n";
  }else{
    print $_[0]." は /P.+?P/ にマッチしません。\n";
  }
}

テキストエディタでプログラムを記述したあと sample.pl という名前で保存します。(文字コードは UTF-8 です)。コマンドプロンプトを起動し、プログラムを保存したディレクトリへ移動したあとで次のように実行します。

perl sample.pl

次のように実行結果が表示されます。

欲張りなマッチと控え目なマッチ(最小量指定子)(1)

同じ文字列に対して最小量指定子が付いている場合と付いていない場合で、文字列のどの部分とマッチするのかを取得し画面に表示しました。なおパターンにマッチした部分を取得するには $& を使用します。詳しくは「マッチした文字列全体を取得($&)」を参照されてください。

-- --

Perl の正規表現で欲張りなマッチと控え目なマッチを行う方法について解説しました。

( Written by Tatsuo Ikura )

Profile
profile_img

著者 / TATSUO IKURA

プログラミングや開発環境構築の解説サイトを運営しています。