パターンをいくつかに分解しそれぞれがマッチした部分を取得する($1, $2, ..)

パターンにマッチした文字列全体を取得するのではなく、パターンの中のそれぞれの部分がマッチした文字列を個別に取得することができます。ここでは Ruby の正規表現でパターンをいくつかに分解しそれぞれがマッチした部分を取得する方法について解説します。

(2021 年 06 月 30 日公開 / 2022 年 10 月 11 日更新)

マッチした複数の文字列を取得

パターンにマッチした文字列全体を取得するだけでなく、パターンをいくつかに分割し、それぞれの部分にマッチした文字列を取得することができます。次の例を見てください。

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

変数 $& にはパターン全体ににマッチした「1980yen」が代入されます。ではパターンの中の「\d+」及び「yen」にそれぞれどの部分がマッチしたのかを取得してみます。その場合は「\d+」及び「yen」を () で括ってください。

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

パターンの一部を () で括ると、その部分にマッチした部分を個別に取得できるようになります。

今回は「\d+」と「yen」が () で括られています。パターンがマッチすると、 1 番目の括弧で囲まれたパターンにマッチした部分が特別な変数 $1 に格納され、 2 番目ので囲まれたパターンにマッチした部分が変数 $2 に格納されます。( 3 個以上ある場合も同じです)。

変数 $1 と変数 $2 を参照することで、「\d+」と「yen」がどの部分とマッチしたのかを取得できます。

$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")
サンプルコード

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

# encoding: UTF-8

def check(str)
  if /((\d+)(yen))/ =~ str then
    puts("○" + str)
    puts("  [" + $1 + "]")
    puts("  [" + $2 + "]")
    puts("  [" + $3 + "]")
  else
    puts("×" + str)
  end
end

puts("((\d+)(yen)) にマッチするかどうか")

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

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

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

-- --

Ruby の正規表現でパターンをいくつかに分解しそれぞれがマッチした部分を取得する方法について解説しました。

( Written by Tatsuo Ikura )

広告
Profile
profile_img

著者 / TATSUO IKURA

初心者~中級者の方を対象としたプログラミング方法や開発環境の構築の解説を行うサイトの運営を行っています。