RegExp.prototype.exec()
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
試してみましょう
構文
exec(str)
引数
str
-
正規表現の照合を実施する文字列。すべての値は文字列に強制されますので、省略したり
undefined
を渡したりするとexec()
は文字列"undefined"
を検索するようになりますが、これは望むところではないでしょう。
返値
照合に失敗した場合は、 exec()
メソッドは null
を返し、 lastIndex
を 0
に設定します。
照合に成功した場合、 exec()
メソッドは配列を返し、正規表現オブジェクトの lastIndex
プロパティを更新します。返された配列は、一致したテキストを最初の項目として持ち、その後、一致したテキストの括弧によるキャプチャグループに対して 1 つずつの項目を持ちます。
index
-
文字列中で一致した位置の 0 から始まるインデックスです。
input
-
照合対象であった元の文字列です。
groups
-
名前付きキャプチャグループを示す
null
プロトタイプオブジェクトで、そのキーが名前となり、値がキャプチャグループ、またはキャプチャグループが定義されていなければundefined
です。詳しくはキャプチャグループを参照してください。 indices
省略可-
このプロパティは
d
フラグが設定されている場合にのみ存在します。これは配列で、それぞれの要素は部分文字列の一致した境界を表します。この配列のそれぞれの要素のインデックスはexec()
が返す配列の中の一致する部分文字列のインデックスに対応します。言い換えれば、最初のindices
項目は照合する文字列全体を表し、2 つ目のindices
項目は最初のキャプチャグループなどを表します。各項目自身は 2 要素の配列で、最初の数字は一致の開始インデックスを表し、2 つ目の数字はその終了インデックスを表します。配列
indices
にはさらにgroups
プロパティがあり、すべての名前付きキャプチャグループのnull
プロトタイプオブジェクトを保持します。キーはキャプチャグループの名前であり、それぞれの値は 2 つ要素の配列で、最初の数字はキャプチャグループの始めるインデックス、 2 つ目の数字は終わりのインデックスです。正規表現に名前付きキャプチャグループが含まれていない場合、groups
はundefined
となります。
解説
JavaScript の RegExp
オブジェクトは、 global または sticky フラグが設定されている場合(例えば /foo/g
や /foo/y
)はステートフルになります。これは前回の一致位置を lastIndex
に格納します。これを内部的に使用することで、 exec()
はテキストの文字列内で(キャプチャグループのある)複数の一致を反復処理することができます。これは単なる文字列の一致を取得する String.prototype.match()
とは対照的です。
exec()
を使用する場合、グローバルフラグは sticky フラグが設定されているときには影響しません。照合は常に粘着的に行われます。
exec()
は正規表現のプリミティブメソッドです。他の多くの正規表現メソッドは、内部的に exec()
を呼び出します。これは [Symbol.replace]()
のような文字列のメソッドからも呼び出されます。exec()
自体は強力ですが(そして最も効率的です)、多くの場合、最も明確に意図を伝えるものではありません。
- 正規表現が文字列に一致するかどうかだけが必要で、実際に何が一致するかを見る必要がない場合は、代わりに
RegExp.prototype.test()
を使用してください。 - グローバル正規表現のすべての出現を探す場合で、キャプチャグループのような情報が不要な場合は、代わりに
String.prototype.match()
を使用してください。さらに、String.prototype.matchAll()
は、一致した文字列を反復処理することで、(キャプチャグループを持つ)文字列の複数の部分の照合を簡略化するのに役立ちます。 - 文字列内の位置のインデックスを知るため照合する場合は、代わりに
String.prototype.search()
メソッドを使用してください。
例
exec() の使用
次の例を想像してみてください。
// "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.lastIndex
は 25
に設定されます。
連続した一致の検索
正規表現で g
フラグを使用する場合、同じ文字列で成功する一致を見つけるために exec()
メソッドを複数回使うことができます。その際、検索は正規表現オブジェクトの lastIndex
プロパティで指定された位置の str
の部分文字列から始まります(test()
も lastIndex
プロパティの位置から始めます)。なお、別な文字列を検索する場合でも lastIndex
プロパティはリセットされず、既存の lastIndex
から検索を始めます。
例えば、次のスクリプトを考えてみてください。
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()
を使用することもできます。
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