Подтвердить что ты не робот

RegExp.exec() возвращает NULL спорадически

Я серьезно схожу с ума по этому поводу, и я уже потратил непропорциональное количество времени на попытку выяснить, что происходит здесь. Поэтому, пожалуйста, дайте мне руку =)

Мне нужно выполнить некоторое соответствие RegExp строк в 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>");
    }
}

Возвращает "cat" и "dog" для первых двух элементов, как и должно быть, но затем некоторые exec() -calls начинают возвращать null. Я не понимаю, почему.

Я разместил здесь Fiddle где вы можете запускать и редактировать код.

И пока я пробовал это в Chrome и Firefox.

Ура!

/Christofer

4b9b3361

Ответ 1

О, вот оно. Поскольку вы определяете глобальное выражение regex, оно соответствует первому cat и второму проходу цикла dog. Итак, в основном вам просто нужно reset ваше регулярное выражение (его внутренний указатель). Ср это:

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);
}

Ответ 2

Объект regex имеет свойство lastIndex, которое обновляется при запуске exec. Поэтому, когда вы выполняете регулярное выражение, например, "У меня есть кошка и собака тоже". lastIndex устанавливается в 12. При следующем запуске exec в том же объекте регулярного выражения он начинает искать индекс 12. Таким образом, вы должны reset lastIndex между каждым прогоном.

Ответ 3

Две вещи:

  • Указанная потребность reset при использовании флага g (global). Чтобы решить эту проблему, я рекомендовал просто назначить 0 члену lastIndex объекта RegExp. Это улучшает производительность, чем уничтожает и восстанавливает.
  • Будьте осторожны, когда используйте ключевое слово in, чтобы пройти объект Array, потому что это может привести к неожиданным результатам с некоторыми lib. Иногда вам нужно проверить с чем-то вроде isNaN(i), или если вы знаете, что у него нет отверстий, используйте классический для цикла.

Код может быть:

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>");
    }
  }

Ответ 4

У меня была аналогичная проблема с использованием только /g, и предлагаемое решение здесь не работало для меня в FireFox 3.6.8. Я получил script с

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

Я добавляю это, если у кого-то другая проблема, с которой я столкнулся с вышеупомянутым решением.