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

正規表現のパターンの一部を括弧()で括ることで、パターンが文字列にマッチしたときに括弧でくくった部分がどの部分にマッチしたのを取得できます。パターン内に複数の括弧を記述した場合でも、特別な変数を参照することでそれぞれどの部分にマッチしたのかを取得できます。ここでは Perl の正規表現でマッチした複数の文字列を取得する方法について解説します。

(Last modified: )

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

例えば次のようなパターンを記述したとします。

/\d+yen/

このパターンが対象の文字列にマッチした場合、文字列の中のどの部分とパターンがマッチしたのかは $& を使って参照することができます。ここでこのパターンの中の \d+yen の部分がそれぞれどの部分にマッチしたのかを調べるには、調べたい部分を括弧 () で括ります。

/(\d+)(yen)/

このパターンが対象の文字列にマッチすると、最初の括弧に囲まれたパターンの一部分が文字列にマッチした部分が特別な変数 $1 に格納されます。また次の括弧に囲まれた部分がマッチした部分が特別な変数 $2 に格納されます。

この $1 などを参照することで、パターン全体がマッチした部分だけでなく、パターンの中の一部分がマッチした文字列全体のどの部分にマッチしたのかを取得できます。

具体的な例で確認します。対象の文字列が "book is 2045yen" の場合にパターンを (\d+)(yen) としています。

my $str = "book is 2045yen";

if ($str =~ /(\d+)(yen)/){
  print "$1\n";
  print "$2\n";
}

パターン全体は "2045yen" にマッチします。マッチに成功した時、最初の括弧内に記述されたパターン \d+ には "2045" がマッチし、変数 $1 に格納されます。また、次の括弧内に記述されたパターン yen には "yen" がマッチし、変数 $2 に格納されます。

今回は 2 つ括弧を使用していますが 3 つ以上の括弧を記述した場合は $3$4 といった変数に格納されていきます。

$&の代わりにマッチした全体を取得する

パターン全体にマッチした文字列は、特別な変数 $& を参照することで確認できますが、パターン全体を () で括っておくことで、特別な変数 $1 を参照することでパターン全体にマッチした文字列を取得できます。

my $str = "book is 2045yen";

if ($str =~ /(\d+yen)/){
  print "$1\n";
}

$& よりは $1 を利用した方がパフォーマンス的にいいということです。

括弧と変数の関係

パターンの中に括弧がある場合、マッチした文字列は順に特別な変数 $1$2 へ順に格納されていきます。格納される順番はパターンの中で ( が現れた順となります。

例えば次のパターンであれば、パターの中に括弧は 2 つあり、 ( が現れた順に次のように変数にマッチした部分が格納されます。

/(\d+)(yen)/
$1 --> \d+
$2 --> yen

またパターンの中で括弧 () は重複した範囲を括ることができます。例えば次のような場合です。

/((\d+)(yen))/

この場合、格納される変数と対応するパターンの関係は次の通りです。

/((\d+)(yen))/

$1 --> \d+yen
$2 --> \d+
$3 --> yen

パターンの中で最初に現れる ( はパターン全体を括っています。2番目の (\d+ を、3番目の (yen を括っています。よって各変数に対応するパターンは上記のようになります。対象の文字列が "book is 2045yen" だった場合、それぞれの変数に格納される値は次の通りです。

/((\d+)(yen))/

$1 <-- 2045yen
$2 <-- 2045
$3 <-- yen
サンプルコード

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

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

&check("book is 2000yen, cake is 800yen");
&check("orange is 950yen");

sub check{
  if ($_[0] =~ /((\d+)(yen))/){
    print $_[0]." は /((\\d+)(yen))/ にマッチします。\n";
    print "\$1: $1\n";
    print "\$2: $2\n";
    print "\$3: $3\n";
  }
}

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

perl sample.pl

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

マッチした複数の文字列を取得する(1)

パターンの中を括弧で囲うことで、パターンの中のどの部分が対象の文字列のどの部分にマッチしたのかを取得し、それぞれ画面に出力しました。

-- --

Perl の正規表現でマッチした複数の文字列を取得する方法について解説しました。

( Written by Tatsuo Ikura )

プロフィール画像

著者 / TATSUO IKURA

これから IT 関連の知識を学ばれる方を対象に、色々な言語でのプログラミング方法や関連する技術、開発環境構築などに関する解説サイトを運営しています。