正規表現にマッチした文字列を取得する(RegExp.prototype.exec)

RegExp オブジェクトのインスタンスメソッドである exec は、対象の文字列が正規表現とマッチした場合、マッチした部分の文字列を取得します。また正規表現のパターンにキャプチャグループが含まれていた場合は、キャプチャグループにマッチした文字列も併せて取得します。ここでは RegExp オブジェクトの exec メソッドの使い方について解説します。

(Last modified: )

execメソッドの使い方

RegExp オブジェクトの exec メソッドは、対象となる文字列が正規表現とマッチした場合に、マッチした文字列を取得します。書式は次の通りです。

正規表現オブジェクト.exec(文字列)

引数に指定した文字列が正規表現とマッチした場合は、マッチした文字列が格納された配列を返します。マッチしなかった場合は null を返します。戻り値の配列にはインデックス 0 の要素にパターン全体にマッチした文字列、インデックス 1 以降の要素には設定したキャプチャグループで囲んだパターンにマッチした文字列が格納されます。(キャプチャグループを設定していない場合はインデックス 1 以降の要素は存在しません)。

配列[0]  パターン全体にマッチした文字列
配列[1]  キャプチャグループ1にマッチした文字列
配列[2]  キャプチャグループ2にマッチした文字列
・・・
配列[n]  キャプチャグループnにマッチした文字列

次のサンプルをみてください。最初にキャプチャグループが含まれないパターンの場合です。

let regexp = /20\d{2}-\d{2}-\d{2}/;

let result1 = regexp.exec('Today is 2020-08-14');
console.log(result1[0]);
>> 2020-08-14

let result2 = regexp.exec('Yesterday is 1998-12-07');
console.log(result2[0]);
>> TypeError: Cannot read property '0' of null

文字列が正規表現にマッチした場合には、パターン全体がマッチした文字列がインデックス 0 の要素の値として格納された配列として受け取ります。ただマッチしなかった場合には戻り値は null となり、 null に対してインデックス 0 の要素を取得しようとすると TypeError が発生します。次のように null かどうかの条件分岐を追加するか例外処理を行ってください。

let regexp = /20\d{2}-\d{2}-\d{2}/;

let result = regexp.exec('Yesterday is 1998-12-07');
if (result !== null){
  console.log(result[0]);
}else{
  console.log('Not Match');
}

>> Not Match

パターンにキャプチャグループが含まれる場合

続いてパターンにキャプチャグループが含まれている場合です。キャプチャグループを作成するには、パターンの中を括弧()で囲います。するとキャプチャグループに設定したパターンの部分にマッチした文字列を取得することができます。

次のサンプルを見てください。

let regexp = /(20\d{2})-(\d{2})-(\d{2})/;

let result = regexp.exec('Today is 2020-08-14');
for (let i = 0 ; i < result.length ; i++){
  console.log('i=' + i + ', match=' + result[i]);
}

>> i=0, match=2020-08-14
>> i=1, match=2020
>> i=2, match=08
>> i=3, match=14

文字列が正規表現にマッチした場合は、戻り値として配列を受け取ります。インデックス 0 の要素にはパターン全体がマッチした文字列が格納され、インデックス 1 以降の要素にはそれぞれキャプチャグループで囲まれたパターンにマッチした文字列が格納されています。

今回はキャプチャグループが 3 つパターンに含まれているので、インデックス 1 からインデックス 3 までの要素にそれぞれキャプチャした文字列が格納されています。

マッチした文字列の位置を参照する

exec メソッドを実行して文字列が正規表現にマッチした場合、マッチした文字列の先頭文字のインデックスが戻り値として取得した配列の index プロパティに設定されます。そこで index プロパティを参照することでマッチした文字列の位置を参照することができます。インデックスは対象の文字列の先頭文字が 0 、次の文字が 1 、と続いていきます。

次のサンプルをみてください。

let regexp = /20\d{2}-\d{2}-\d{2}/;

let result = regexp.exec('Today is 2020-08-14');
console.log(result[0]);
>> 2020-08-14
console.log('lastIndex=' + result.index);
>> lastIndex=9

マッチした文字列の位置を参照する(1)

対象の文字列の中で、正規表現にマッチした文字列の先頭文字のインデックスを参照することができました。

グローバルフラグが設定されている場合

パターンの最後に g を記述するとグローバルフラグを設定することができます。

/パターン/g

正規表現にグローバルフラグが設定されている場合、 exec メソッドを実行し文字列が正規表現にマッチすると、正規表現オブジェクトの lastIndex プロパティの値がマッチした文字列の次の文字のインデックスに設定されます。(グローバルフラグが設定されていない場合は、 exec メソッドでマッチしたとしても lastIndex は 0 のままです)。

let regexp = /[A-Z].+?day/g;
let str = 'Sunday Monday Tuesday';

let result = regexp.exec(str);
console.log(result[0]);
>> Sunday
console.log('lastIndex=' + regexp.lastIndex);
>> lastIndex=6

グローバルフラグが設定されている場合(1)

そのあとで同じ正規表現に対して同じ文字列を引数に指定して exec メソッドを実行すると、現在の lastIndex が示す文字列の位置から正規表現とマッチする文字列を取得します。再びマッチした場合は、改めて lastIndex プロパティの値が更新されます。

let regexp = /[A-Z].+?day/g;
let str = 'Sunday Monday Tuesday';

let result = regexp.exec(str);
console.log(result[0]);
>> Sunday
console.log('lastIndex=' + regexp.lastIndex);
>> lastIndex=6

result = regexp.exec(str);
console.log(result[0]);
>> Monday
console.log('lastIndex=' + regexp.lastIndex);
>> lastIndex=13

グローバルフラグが設定されている場合(2)

exec メソッドを実行したときに正規表現にマッチしなかった場合には lastIndex は 0 に戻ります。

let regexp = /[A-Z].+?(day)/g;
let str = 'Sunday Monday Tuesday';

let result = regexp.exec(str);
while (result !== null){
  console.log(result[0]);
  console.log(result[1]);
  console.log('lastIndex=' + regexp.lastIndex);

  result = regexp.exec(str);
}
console.log('lastIndex=' + regexp.lastIndex);

>> Sunday
>> day
>> lastIndex=6
>> Monday
>> day
>> lastIndex=13
>> Tuesday
>> day
>> lastIndex=21
>> lastIndex=0

このようにグローバルフラグを設定することで、同じ文字列に対して正規表現が複数回マッチするかどうか確認しマッチした場合はその文字列を取得することができます。

-- --

RegExp オブジェクトの exec メソッドの使い方について解説しました。

( Written by Tatsuo Ikura )

プロフィール画像

著者 / TATSUO IKURA

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