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

正規表現で繰り返しのメタ文字を使用したパターンを作成する場合、対象の文字列の一番長い部分とマッチするのか一番短い部分とマッチするのかなど文字列のどの部分にマッチするのかを注意する必要があります。ここでは Ruby の正規表現で欲張りなマッチと控え目なマッチの違いについて解説します。

(Last modified: )

欲張りなマッチ

繰り返しを意味するメタ文字である「+」、「*」、「?」、「{min,max}」、「{num}」はなるべく長い文字列にマッチしようとします。

/a.+b/

上記の場合「a」で始まり任意の文字(改行除く)が 1 回以上続き「b」で終わる文字列にマッチします。これを「00a11b22b33b44」に対してマッチさせてみるとマッチする部分としては次の 3 つの候補があります。

00a11b22b33b44
00a11b22b33b44
00a11b22b33b44

マッチしたかどうかを考えるだけならば気にしなくても構いませんが、文字列の中のどの部分にマッチしたのかが必要になる時には、どの位置にマッチしたかを考えることは重要です。

このような時、繰り返しを表すメタ文字は一番長い文字列にマッチしようとします。つまりマッチする部分は次の箇所となります。

00a11b22b33b44

なお正規表現オブジェクトに対して =~ メソッドがマッチした場合、マッチした部分が変数 $& に格納されます。その為、マッチに成功したあとで変数 $& を参照すると対象の文字列の中のどの部分にマッチしたかを確認できます。

サンプルコード

では簡単なプログラムで確認してみます。

# encoding: UTF-8

def check(str)
  if /a.+b/ =~ str then
    puts("○" + str + "(" + $& + ")")
  else
    puts("×" + str)
  end
end

puts("「a.+b」にマッチするかどうか")

check("00a11b22b33b44")

下記のように実行して下さい。

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

今回はマッチに成功した場合、マッチした部分も合わせて表示するようにしています。マッチ可能な最大の部分にマッチしていることが確認できます。

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

デフォルトではマッチする範囲が最大になるようにマッチしますが、逆に最小になるようにマッチさせることも可能です。繰り返しを表す各メタ文字のあとに「?」を付けて使用することで最小の部分にマッチするようになります。

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

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

/a.+?b/

上記の場合「a」で始まり任意の文字(改行除く)が 1 回以上続き「b」で終わる文字列にマッチします。これを「00a11b22b33b44」に対してマッチさせてみるとマッチする部分としては次の 3 つの候補があります。

00a11b22b33b44
00a11b22b33b44
00a11b22b33b44

今回は最小量指定子の「?」が付けられていますので、最も短い文字列にマッチしようとします。つまりマッチする部分は次の箇所となります。

00a11b22b33b44
サンプルコード

では簡単なプログラムで確認してみます。

# encoding: UTF-8

def check(str)
  if /a.+?b/ =~ str then
    puts("○" + str + "(" + $& + ")")
  else
    puts("×" + str)
  end
end

puts("「a.+?b」にマッチするかどうか")

check("00a11b22b33b44")

下記のように実行して下さい。

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

マッチ可能な候補の中で最小の部分にマッチしていることが確認できます。

-- --

Ruby の正規表現で欲張りなマッチと控え目なマッチの違いについて解説しました。

( Written by Tatsuo Ikura )

Profile
profile_img

著者 / TATSUO IKURA

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