RegExp.exec()は散発的にNULLを返します


83

私はこれに真剣に夢中になっていて、ここで何が起こっているのかを理解しようとすることにすでに不釣り合いな時間を費やしています。だから私に手を貸してください=)

JavaScriptで文字列の正規表現マッチングを行う必要があります。残念ながら、それは非常に奇妙に動作します。このコード:

var rx = /(cat|dog)/gi;
var w = new Array("I have a cat and a dog too.", "There once was a dog and a cat.", "I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.");

for (var i in w) {
    var m = null;
    m = rx.exec(w[i]);
    if(m){
        document.writeln("<pre>" + i + "\nINPUT: " + w[i] + "\nMATCHES: " + m.slice(1) + "</pre>");
    }else{
        document.writeln("<pre>" + i + "\n'" + w[i] + "' FAILED.</pre>");
    }
}

最初の2つの要素に対して「cat」と「dog」を返す必要がありますが、その後、一部のexec()-callがnull。を返し始めます。理由がわかりません。

ここにフィドルを投稿しました。ここで、コードを実行および編集できます。

そしてこれまで、ChromeとFirefoxでこれを試しました。

乾杯!

/クリストファー


でのみ失敗"I have a cat and a dog too."するようです
SilentGhost 2011年

設計上一致が失敗した場合、execはnullを返すため、何らかの理由で一致に失敗します。
Martin Jespersen 2011年

回答:


79

ああ、ここにあります。正規表現をグローバルに定義しているため、最初に一致しcat、ループの2番目のパスで一致しますdog。したがって、基本的には、正規表現(内部ポインター)もリセットする必要があります。Cf. この:

var w = new Array("I have a cat and a dog too.", "I have a cat and a dog too.", "I have a cat and a dog too.", "I have a cat and a dog too.");

for (var i in w) {
    var rx = /(cat|dog)/gi;
    var m = null;
    m = rx.exec(w[i]);
    if(m){
        document.writeln("<p>" + i + "<br/>INPUT: " + w[i] + "<br/>MATCHES: " + w[i].length + "</p>");
    }else{
        document.writeln("<p><b>" + i + "<br/>'" + w[i] + "' FAILED.</b><br/>" + w[i].length + "</p>");
    }
    document.writeln(m);
}

そこにあります、私は遅すぎました:)
Martin Jespersen 2011年

ああ甘い!それを理解するのに少し時間がかかったでしょう。ありがとう!
cpak 2011年

これは私に多くの時間を節約しました。本当にありがとう!
Thomas Johansen 2017年

この問題は私に人生を疑わせます。
GZ Xue 2018

私は給料を
返済する

72

正規表現オブジェクトには、lastIndexを実行すると更新されるプロパティがありますexec。したがって、たとえば「猫と犬もいます。」で正規表現lastIndexを実行するexecと、12に設定されます。次に同じ正規表現オブジェクトを実行すると、インデックス12から検索が開始されます。したがって、lastIndexプロパティをリセットする必要があります。各実行の間に。


ああ、このサイトは私には速すぎます。SilentGhostの+1 :-)
Frode

8
説明してくれてありがとう!myRe.lastIndex = 0;後で使用するために設定することで大いに役立ちます。
アントニー

1
うわー、lastIndexのヒントをどうもありがとう、それは本当に私を夢中にさせました!
dave0688 2018

1
私はそれは同じ正規表現オブジェクトを再利用するのがベストプラクティスに従っているので、これは正しい答えであるべきだと思う
smurtagh

これが正解であることに同意します。同じ正規表現オブジェクトを再利用し、内部の仕組みについても説明します。OPは変更を検討する必要があります。
ショーンコーリー

31

2つのこと:

  1. (グローバル)フラグを使用する場合のリセットの前述の必要性g。これを解決するために、私は単純に割り当て推薦0lastIndexのメンバーRegExpオブジェクト。これは、破棄して再作成するよりもパフォーマンスが優れています。
  2. 一部のライブラリで予期しない結果が発生する可能性があるためオブジェクトをウォークするためにキーワードを使用するinArray場合注意してください。のようなものisNaN(i)で確認する必要がある場合があります。または、穴がないことがわかっている場合は、古典的なforループを使用します。

コードは次のとおりです。

var rx = /(cat|dog)/gi;
w = ["I have a cat and a dog too.", "There once was a dog and a cat.", "I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat."];

for (var i in w)
 if(!isNaN(i))        // Optional, check it is an element if Array could have some odd members.
  {
   var m = null;
   m = rx.exec(w[i]); // Run
   rx.lastIndex = 0;  // Reset
   if(m)
    {
     document.writeln("<pre>" + i + "\nINPUT: " + w[i] + "\nMATCHES: " + m.slice(1) + "</pre>");
    } else {
     document.writeln("<pre>" + i + "\n'" + w[i] + "' FAILED.</pre>");
    }
  }

1
これが正解です。設定rx.lastIndex = 0は、ループ内でRegExオブジェクトを再作成するよりもはるかに優れています。
ミノル

4

/ gのみを使用しても同様の問題が発生しましたが、FireFox3.6.8ではここで提案された解決策は機能しませんでした。スクリプトを使用しました

var myRegex = new RegExp("my string", "g");

他の誰かが上記の解決策で私がしたのと同じ問題を抱えている場合に備えて、これを追加しています。

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