RegExpのexec()関数とStringのmatch()関数の違いは何ですか?


122

これを実行すると:

/([^\/]+)+/g.exec('/a/b/c/d');

私はこれを手に入れます:

["a", "a"]

しかし、これを実行すると:

'/a/b/c/d'.match(/([^\/]+)+/g);

次に、これの期待される結果が得られます。

["a", "b", "c", "d"]

違いは何ですか?


4
ループしexecてすべてのサブ選択を取得します。
zzzzBov

2
2番目の +matchすでにすべてのサブ式を返すためは必要ない。.exec毎回1つだけを返すため、それも必要ありません+
pimvdb

3
その上、2つのプラスのようなネストされた数量詞は非常に慎重に使用する必要があります。 壊滅的なバックトラック
Marius Schulz

1
@MariusSchulzリンクをありがとう。それから、所有格指定子と原子グループについて学びました。理解するのにとても良いこと。
Justin Warkentin 2013

回答:


117

execグローバル正規表現を使用すると、一致したすべての部分式が引き続き取得されるため、ループで使用することが意図されています。そう:

var re = /[^\/]+/g;
var match;

while (match = re.exec('/a/b/c/d')) {
    // match is now the next match, in array form.
}

// No more matches.

String.match これはあなたのために行われ、キャプチャされたグループを破棄します。


39
この答えに追加するものwhile(match = /[^\/]+/g.exec('/a/b/c/d')があります。このように、while条件内に正規表現リテラルを配置しないでください。そうしないと、無限ループが発生します!。それは明確にMDNに述べていますようdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
yeyo

7
@yeyo:より具体的には、同じ正規表現オブジェクトでなければなりません。リテラルはそれを達成しません。
Ry-

@ Ry-この動作はES5で導入されたことに注意してください。ES5前new RegExp("pattern")/pattern/異なることを意味しました。
Robert

75

1つの画像の方がいいですよね。

re_once = /([a-z])([A-Z])/
re_glob = /([a-z])([A-Z])/g

st = "aAbBcC"

console.log("match once="+ st.match(re_once)+ "  match glob="+ st.match(re_glob))
console.log("exec once="+ re_once.exec(st) + "   exec glob="+ re_glob.exec(st))
console.log("exec once="+ re_once.exec(st) + "   exec glob="+ re_glob.exec(st))
console.log("exec once="+ re_once.exec(st) + "   exec glob="+ re_glob.exec(st))

違いを見ます?

注:強調表示するために、キャプチャされたグループ(例:a、A)は一致したパターン(例:aA)の後に返されることに注意してください。これは一致したパターンだけではありません。


28

/regex/.exec()正規表現でフラグ"string".match()を使用する場合、最初に見つかった一致のみを返しますが、すべてを返しますg

ここを参照してください:execmatch


23

正規表現がグローバルであり、キャプチャしている場合は、execを使用する必要があります。Matchはすべてのキャプチャを返しません。

一致は、単に一致する場合(キャプチャしない場合)に最適です。一度実行すると、すべての一致の配列が得られます。(ただし、正規表現がグローバルではない場合、一致すると一致が表示され、その後にキャプチャが表示されます)

execはキャプチャ時に使用するもので、実行されるたびに一致が得られ、その後にキャプチャが続きます。(一致は、正規表現がグローバルでない場合にのみ、完全一致の後にキャプチャが続くように動作します)。

Execのもう1つの用途は、一致のインデックスまたは位置を取得することです。正規表現の変数がある場合、.lastIndexを使用して、一致する位置を取得できます。正規表現オブジェクトには.lastIndexがあり、正規表現オブジェクトは.execを実行する対象です。ドットマッチは文字列に対して行われ、正規表現オブジェクトドットlastIndexを実行できなくなります

文字列には、正規表現が渡されるmatch関数があります。そして、正規表現、exec関数があり、文字列が渡されます

複数回実行するexec。一度走るとマッチする

キャプチャしない場合とキャプチャする場合に一致を使用することは良いです。キャプチャを取得するのに適しているため、より強力なexecを使用できますが、キャプチャ時に一致を使用した場合は、正規表現がグローバルではないときにキャプチャが表示されることを確認してください。正規表現がグローバルな場合はキャプチャを表示しません。

> "azb".match(/a(z)b/);
[ "azb", "z" ]

> "azb".match(/a(z)b/g);
[ "azb" ]
>

もう1つは、execを使用すると、正規表現で呼び出されることに注意してください。正規表現に変数を使用すると、より強力になります。

正規表現に変数を使用しない場合は一致が得られないため、execを使用する場合は正規表現に変数を使用します

> /./g.exec("abc")
[ "a" ]
> /./g.exec("abc")
[ "a" ]
> /./g.exec("abc")
[ "a" ]
>
> /[a-c]/g.exec("abc")
[ "a" ]
> /[a-c]/g.exec("abc")
[ "a" ]
>

> var r=/[a-c]/g
> r.exec("abc")
[ "a" ]
> r.exec("abc")
[ "b" ]
> r.exec("abc")
[ "c" ]
> r.exec("abc")
null
>

execを使用すると、一致の「インデックス」を取得できます

> var r=/T/g
> r.exec("qTqqqTqqTq");
[ "T" ]
> r.lastIndex
2
> r.exec("qTqqqTqqTq");
[ "T" ]
> r.lastIndex
6
> r.exec("qTqqqTqqTq");
[ "T" ]
> r.lastIndex
9
> r.exec("qTqqqTqqTq");
null
> r.lastIndex
0
>

したがって、インデックスまたはキャプチャが必要な場合は、execを使用します(ご覧のように、「インデックス」を指定すると、インデックスが与える「インデックス」は実際にはn番目のオカレンスであり、1から数えます。したがって、適切な1を引いてインデックスを作成します。ご覧のとおり、0-lastIndex of 0-not foundが表示されます)。

そして、マッチをストレッチしたい場合は、キャプチャ時に使用できますが、正規表現がグローバルである場合は使用できません。そのためにそれを行うと、配列の内容はすべてのマッチではなく、完全です試合に続いて捕獲。


はい、の作業を理解することr.lastIndexの違いを理解するために重要な要因であるexecとしますmatch
-runun

@barlop「マッチはすべてのキャプチャと一致しない」、真剣に?"a、b、c、aa、bb、cc" .match(/(\ w +)/ g)=> ["a"、 "b"、 "c"、 "aa"、 "bb"、 "cc" ]。それらのすべてをキャッシュしたことをどのように説明しますか?
MrHIDEn

@barlop If your regex is global, and you are capturing, then you must use exec. Match won't return all your captures.私はコンソールでそれを得ました。"a,b,c,aa,bb,cc".match(/(\w+)/g);Opera、Firefoxをコピーして貼り付けてください。
MrHIDEn

@MrHIDEn間違った引用で使用した言語を使用しないでください。そして重要なのは、何が表示され、何が見えるかということです。舞台裏にキャッシュがあるかどうかも関係ありません。そして、私はこれに見えたので、それはしばらくしているが、それはすべてのキャプチャが表示されない..あなたはあなたの例を行う場合であっても"a,b,c,aa,bb,cc".match(/(\w+)/g) 、それがあると何が起こっているので、すべての一致を示しており、ちょうどので、あなたはすべての試合を撮影していることが起こりますすべてのキャプチャを表示する場合、まったく同じように見えます(cntd)
barlop

(cntd)だからあなたはそれがキャプチャを示していると思っているかもしれませんが、それはそうではありません、それは試合を示しています
barlop

6

.match()関数は、str.match(regexp)次の手順を実行します。

  • 一致する場合、次を返します。
    • gフラグ正規表現で使用されている場合:すべての部分文字列を返します(キャプチャグループは無視されます)
    • gフラグが正規表現で使用されていない場合:次と同じ結果を返しますregexp.exec(str)
  • 一致しない場合は、次を返します。
    • null

フラグを使用した.match()のg

var str = "qqqABApppabacccaba";
var e1, e2, e3, e4, e5;
e1 = str.match(/nop/g); //null
e2 = str.match(/no(p)/g); //null
e3 = str.match(/aba/g); //["aba", "aba"]
e4 = str.match(/aba/gi); //["ABA", "aba", "aba"]
e5 = str.match(/(ab)a/g); //["aba", "aba"] ignoring capture groups as it is using the g flag

そして、.match()なしのgフラグは同等です)(.exec

e1=JSON.stringify(str.match(/nop/))===JSON.stringify(/nop/.exec(str)); //true
//e2 ... e4 //true
e5=JSON.stringify(str.match(/(ab)a/))===JSON.stringify(/(ab)a/.exec(str)); //true

.exec()関数は、regexp.exec(str)次の手順を実行します。

  • 一致する場合、次を返します。
    • 場合gフラグがされている正規表現で使用される:それが返され(それが呼び出されるたびにするため)[N_MatchedStr, N_Captured1, N_Captured2, ...]次のN試合。重要:正規表現オブジェクトが変数に格納されていない場合は、次の一致に進みません(同じオブジェクトである必要があります)
    • gフラグが正規表現で使用されていない場合:gフラグがあり、初めて呼び出された場合と同じように返されます。
  • 一致しない場合は、次を返します。
    • null

.exec()の例(保存された正規表現+ gフラグを使用=呼び出しごとに変化します):

var str = "qqqABApppabacccaba";
var myexec, rgxp = /(ab)a/gi;

myexec = rgxp.exec(str);
console.log(myexec); //["ABA", "AB"]
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "ab"]
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "ab"]
myexec = rgxp.exec(str);
console.log(myexec); //null

//But in this case you should use a loop:
var mtch, myRe = /(ab)a/gi;
while(mtch = myRe.exec(str)){ //infinite looping with direct regexps: /(ab)a/gi.exec()
    console.log("elm: "+mtch[0]+" all: "+mtch+" indx: "+myRe.lastIndex);
    //1st iteration = elm: "ABA" all: ["ABA", "AB"] indx: 6
    //2nd iteration = elm: "aba" all: ["aba", "ab"] indx: 12
    //3rd iteration = elm: "aba" all: ["aba", "ab"] indx: 18
}

.exec()それがされていない各呼び出しで変更:

var str = "qqqABApppabacccaba", myexec, myexec2;

//doesn't go into the next one because no g flag
var rgxp = /(a)(ba)/;
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "a", "ba"]
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "a", "ba"]
//... ["aba", "a", "ba"]

//doesn't go into the next one because direct regexp
myexec2 = /(ab)a/gi.exec(str);
console.log(myexec2); //["ABA", "AB"]
myexec2 = /(ab)a/gi.exec(str);
console.log(myexec2); //["ABA", "AB"]
//... ["ABA", "AB"]

1

時々 )(regex.execかかりますずっと)(string.matchそして、より多くの時間を。

string.match()とregex.exec()の結果が同じ場合(例:\ gフラグを使用しない場合)、regex.exec()はx2からx30の間のどこかで文字列を取ることを言及する価値があります。一致():

したがって、このような場合、「新しいRegExp()。exec()」のアプローチは、グローバル正規表現が必要な場合(つまり、複数回実行する場合)にのみ使用する必要があります。


1
ベンチマークはありますか?
息子TRAN-グエン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.