マッチした複数の文字列を取得($1, $2, ..)

広告

今までは正規表現オブジェクトのパターンにマッチした文字列を取得していましたが、1つのパターンをいくつかに分割し、それぞれの部分にマッチした文字列を取得することが可能です。

/¥d+yen/ =~ "price is 1980yen"

上記の場合、変数「$&」にはマッチした部分文字列である「1980yen」が代入されていました。では「¥d+」及び「yen」にそれぞれマッチする部分を分けて取得してみます。

/(¥d+)(yen)/ =~ "price is 1980yen"

括弧()はパターン内でグループ化する時にも使用されるものですが、パターン内を括弧()で括ることで、括弧()のパターンにマッチした部分文字列を個々に取り出すことが出来るようになります。

上記の場合は括弧()は2つあり、「¥d+」と「yen」が括弧()で括られています。正規表現オブジェクトのマッチが成功すると1番目の括弧で囲まれたパターンにマッチした部分が特別な変数「$1」に格納され、2番目ので囲まれたパターンにマッチした部分が変数「$2」に格納されます。(括弧が2個以上ある場合も同様です)。

/(¥d+)(yen)/ =~ "price is 1980yen"
$1  =>  "1980"
$2  =>  "yen"

括弧と変数の関係

マッチが成功すると括弧の数だけ変数「$1」や変数「$2」に部分文字列が代入されていきます。と格納されていきます。格納される順番はパターンの中で「(」が現れた順となります。

この時、括弧は重複した範囲を括ることが出来ます。例えば次のように記述できます。

/((¥d+)(yen))/

パターン内で「(」が現れた順に変数「$1」「$2」...に順に部分文字列が代入されていきます。上記の場合、括弧は全部で3つあり、変数との関係は次のようになります。

$1  =>  ((¥d+)(yen))
$2  =>  (¥d+)
$3  =>  (yen)

パターン内で1番最初に出てきた「(」に対応する「)」はパターン全体を括っていますので、変数「$1」にはパターン全体に対するマッチした部分文字列が代入されます。次の「(」と対応する「)」は「¥d+」を括っています。よって変数「$2」には「¥d+」にマッチする部分文字列が代入されます。そして最後の「(」と対応する「)」は「yen」を括っています。同じように変数「$3」には「yen」にマッチする部分文字列が代入されます。

具体的な例では次のようになります。

/((¥d+)(yen))/ =~ "price is 1980yen"
$1  =>  "1980yen"
$2  =>  "1980"
$3  =>  "yen"

Regexp.last_match

Regexpクラスで用意されているクラスメソッドの「last_match」を使っても変数「$1」「$2」などと同じ文字列を取得出来ます。

Regexp.last_match([nth])

変数「$1」と同じ部分文字列を取得するには引数に「1」を、変数「$2」と同じ部分文字列をを取得するには引数い「2」を指定して下さい。(引数に0を指定すると変数「$&」と同じくマッチした全体を取得します)。

/((¥d+)(yen))/ =~ "price is 1980yen"
print(Regexp.last_match(1) + "¥n")
print(Regexp.last_match(2) + "¥n")
print(Regexp.last_match(3) + "¥n")

サンプルプログラム

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

test3-1.rb

#! ruby -Ku
require "kconv"

def check(str)
  if /((¥d+)(yen))/ =~ str then
    print(Kconv.tosjis("○") + str + "¥n")
    print("  [" + $1 + "]¥n")
    print("  [" + $2 + "]¥n")
    print("  [" + $3 + "]¥n")
  else
    print(Kconv.tosjis("×") + str + "¥n")
  end
end

print(Kconv.tosjis("((¥d+)(yen)) にマッチするかどうか¥n¥n"))

check("1980yen")
check("340yen")

上記のプログラムを「test3-1.rb」として保存します。文字コードはUTF-8です。そして下記のように実行して下さい。

マッチした複数の文字列を取得($1, $2, ..)

( Written by Tatsuo Ikura )