RegExp.prototype.exec()

exec()RegExp インスタンスのメソッドで、指定された文字列の中でこの正規表現と一致するものを検索し、その結果の配列、または null を返します。

試してみましょう

構文

js
exec(str)

引数

str

正規表現の照合を実施する文字列。すべての値は文字列に強制されますので、省略したり undefined を渡したりすると exec() は文字列 "undefined" を検索するようになりますが、これは望むところではないでしょう。

返値

照合に失敗した場合は、 exec() メソッドは null を返し、 lastIndex0 に設定します。

照合に成功した場合、 exec() メソッドは配列を返し、正規表現オブジェクトの lastIndex プロパティを更新します。返された配列は、一致したテキストを最初の項目として持ち、その後、一致したテキストの括弧によるキャプチャグループに対して 1 つずつの項目を持ちます。

index

文字列中で一致した位置の 0 から始まるインデックスです。

input

照合対象であった元の文字列です。

groups

名前付きキャプチャグループを示す null プロトタイプオブジェクトで、そのキーが名前となり、値がキャプチャグループ、またはキャプチャグループが定義されていなければ undefined です。詳しくはキャプチャグループを参照してください。

indices 省略可

このプロパティは d フラグが設定されている場合にのみ存在します。これは配列で、それぞれの要素は部分文字列の一致した境界を表します。この配列のそれぞれの要素のインデックスは exec() が返す配列の中の一致する部分文字列のインデックスに対応します。言い換えれば、最初の indices 項目は照合する文字列全体を表し、2 つ目の indices 項目は最初のキャプチャグループなどを表します。各項目自身は 2 要素の配列で、最初の数字は一致の開始インデックスを表し、2 つ目の数字はその終了インデックスを表します。

配列 indices にはさらに groups プロパティがあり、すべての名前付きキャプチャグループの null プロトタイプオブジェクトを保持します。キーはキャプチャグループの名前であり、それぞれの値は 2 つ要素の配列で、最初の数字はキャプチャグループの始めるインデックス、 2 つ目の数字は終わりのインデックスです。正規表現に名前付きキャプチャグループが含まれていない場合、 groupsundefined となります。

解説

JavaScript の RegExp オブジェクトは、 global または sticky フラグが設定されている場合(例えば /foo/g/foo/y)はステートフルになります。これは前回の一致位置を lastIndex に格納します。これを内部的に使用することで、 exec() はテキストの文字列内で(キャプチャグループのある)複数の一致を反復処理することができます。これは単なる文字列の一致を取得する String.prototype.match() とは対照的です。

exec() を使用する場合、グローバルフラグは sticky フラグが設定されているときには影響しません。照合は常に粘着的に行われます。

exec() は正規表現のプリミティブメソッドです。他の多くの正規表現メソッドは、内部的に exec() を呼び出します。これは @@replace のような文字列のメソッドからも呼び出されます。exec() 自体は強力ですが(そして最も効率的です)、多くの場合、最も明確に意図を伝えるものではありません。

  • 正規表現が文字列に一致するかどうかだけが必要で、実際に何が一致するかを見る必要がない場合は、代わりに RegExp.prototype.test() を使用してください。
  • グローバル正規表現のすべての出現を探す場合で、キャプチャグループのような情報が不要な場合は、代わりに String.prototype.match() を使用してください。さらに、 String.prototype.matchAll() は、一致した文字列を反復処理することで、(キャプチャグループを持つ)文字列の複数の部分の照合を簡略化するのに役立ちます。
  • 文字列内の位置のインデックスを知るため照合する場合は、代わりにString.prototype.search()メソッドを使用してください。

exec() の使用

次の例を想像してみてください。

js
// "quick brown" の後に "jumps" が来るものを、その間の文字を無視して一致させます。
// "brown" と "jumps" を取得します。
// 大文字と小文字は区別しません。
const re = /quick\s(?<color>brown).+?(jumps)/dgi;
const result = re.exec("The Quick Brown Fox Jumps Over The Lazy Dog");

このスクリプト実行後の result の状態は次のようになります。

プロパティ
[0] "Quick Brown Fox Jumps"
[1] "Brown"
[2] "Jumps"
index 4
indices [[4, 25], [10, 15], [20, 25]]
groups: { color: [10, 15 ]}
input "The Quick Brown Fox Jumps Over The Lazy Dog"
groups { color: "brown" }

それに加えて、この正規表現がグローバルであるため、 re.lastIndex25 に設定されます。

連続した一致の検索

正規表現で g フラグを使用する場合、同じ文字列で成功する一致を見つけるために exec() メソッドを複数回使うことができます。その際、検索は正規表現オブジェクトの lastIndex プロパティで指定された位置の str の部分文字列から始まります({jsxref("RegExp.prototype.test()", "test()")}} も lastIndex プロパティの位置から始めます)。なお、別な文字列を検索する場合でも lastIndex プロパティはリセットされず、既存の lastIndex から検索を始めます。

例えば、次のスクリプトを考えてみてください。

js
const myRe = /ab*/g;
const str = "abbcdefabh";
let myArray;
while ((myArray = myRe.exec(str)) !== null) {
  let msg = `${myArray[0]} を見つけました。`;
  msg += `次の照合は ${myRe.lastIndex} からです。`;
  console.log(msg);
}

このスクリプトは以下のテキストを表示します。

abb を見つけました。次の照合は 3 からです。
ab を見つけました。次の照合は 9 からです。

警告: 無限ループに陥る落とし穴がたくさんあります。

  • 正規表現リテラル(または RegExp コンストラクター)を while 条件内に配置しないでください。反復処理するたびに正規表現が再作成され、 lastIndex がリセットされます。
  • グローバルフラグ (g) が設定されているかを確認してください。さもないと lastIndex が進行しなくなります。
  • 正規表現が長さゼロの文字(例えば /^/gm)に一致する可能性がある場合、同じ位置に留まるのを避けるために、 lastIndex を毎回手動で増やしてください。

通常、このようなコードを String.prototype.matchAll() で置き換えることで、エラーの可能性を下げることができます。

RegExp リテラルでの exec() の使用

RegExp オブジェクトを作成せずに exec() を使用することもできます。

js
const matches = /(hello \S+)/.exec("This is a hello world!");
console.log(matches[1]);

これで 'hello world!' を含んだメッセージをログ出力します。

仕様書

Specification
ECMAScript Language Specification
# sec-regexp.prototype.exec

ブラウザーの互換性

BCD tables only load in the browser

関連情報