RegExp.exec () епізодично повертає NULL


83

Я серйозно божеволію з цього приводу, і я вже витратив непропорційно багато часу, намагаючись з'ясувати, що тут відбувається. Тож прошу подати мені руку =)

Мені потрібно виконати збіг рядків у 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>");
    }
}

Повертає "кішка" і "собака" для перших двох елементів, як і має бути, але потім деякі exec()-виклики починають повертатися null. Я не розумію чому.

Я розмістив тут скрипку , де ви можете запустити та редагувати код.

І до цього часу я пробував це у Chrome та Firefox.

На здоров’я!

/ Христофер


він виходить з ладу лише "I have a cat and a dog too.", здається
SilentGhost

exec повертає null, якщо збіг не вдається задумом, тому з якихось причин він не збігається.
Martin Jespersen

Відповіді:


79

О, ось воно. Оскільки ви визначаєте свій регулярний вираз у цілому, він відповідає першому catта другому проходженню циклу dog. Отже, вам просто потрібно також скинути свій регулярний вираз (це внутрішній вказівник). Пор. це:

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

ось у нас це було, я був занадто повільним :)
Мартін Єсперсен

ах солодко! мені потрібно було б трохи часу, щоб це зрозуміти. Дякую!
cpak

Це заощадило мені дуже багато часу. Дуже дякую!
Thomas Johansen

Ця проблема змушує мене сумніватися у житті.
GZ Xue

Я відчуваю, що мені слід просто повернути зарплату
cgatian

73

Об'єкт регулярного виразу має властивість, lastIndexяка оновлюється під час запуску exec. Отже, коли ви виконуєте регулярний вираз, наприклад, "У мене є і кіт, і собака.", lastIndexВстановлюється значення 12. Наступного разу, коли ви запускаєте execтой самий об'єкт регулярного виразу, він починає шукати з індексу 12. Отже, вам доведеться скинути lastIndexвластивість між кожним прогоном.


Бах, цей сайт для мене занадто швидкий. +1 для SilentGhost :-)
Frode

9
Дякую за пояснення! Це дуже допомагає, встановлюючи myRe.lastIndex = 0;для подальшого використання.
Ентоні

1
Ого, велике спасибі за підказку з lastIndex, що справді зводило мене з розуму!
dave0688

1
Я думаю, що це повинна бути правильна відповідь, оскільки вона відповідає найкращій практиці повторного використання того самого об’єкта регулярних
виразів

Погодьтеся, це повинна бути правильна відповідь. Він використовує той самий об'єкт регулярного виразу, а також пояснює внутрішню механіку. ОП слід розглянути можливість зміни.
Шон Колі,

31

Дві речі:

  1. Згадана необхідність скидання при використанні g(глобального) прапора. Щоб вирішити цю проблему , я recommed просто правонаступником 0до lastIndexчлену RegExpоб'єкта. Це має кращу продуктивність, ніж знищення та відтворення.
  2. Будьте обережні, використовуючи inключове слово для того, щоб ходити поArray об’єкту, оскільки деякі бібліотеки можуть призвести до несподіваних результатів. Іноді вам слід перевірити 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, і запропоноване рішення тут не працювало для мене у FireFox 3.6.8. Я працюю зі своїм сценарієм

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

Я додаю це на випадок, якщо хтось інший має таку ж проблему, як і я з вищезазначеним рішенням.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.