Почему модификатор "g" дает разные результаты, когда test() вызывается дважды? - программирование
Подтвердить что ты не робот

Почему модификатор "g" дает разные результаты, когда test() вызывается дважды?

С учетом этого кода:

var reg = /a/g;
console.log(reg.test("a"));
console.log(reg.test("a"));

Получаю этот результат:

true
false

Я понятия не имею, как это может произойти. Я тестировал как в Node.js(v8), так и в браузере Firefox.

4b9b3361

Ответ 1

Чтобы решить проблему, вы можете удалить флаг g или reset lastIndex, как в

var reg = /a/g;
console.log(reg.test("a"));
reg.lastIndex = 0;
console.log(reg.test("a"));

Проблема возникает из-за того, что test основывается на exec, который ищет больше совпадений после первого, если передается одна и та же строка, и присутствует флаг g.

15.10.6.3 RegExp.prototype.test(string) # Ⓣ Ⓡ

Выполняются следующие шаги:

  • Пусть совпадение будет результатом оценки алгоритма RegExp.prototype.exec (15.10.6.2) на этом объекте RegExp с использованием строки в качестве аргумента.
  • Если совпадение не null, верните true; else return false.

Ключевой частью exec является шаг 6 15.10.6.2:

6. Пусть global будет результатом вызова внутреннего метода [[Get]] R с аргументом "global".
7. Если глобальное значение false, то пусть я = 0.

Если i не reset равно 0, то exec (и поэтому test) не начинает смотреть начало строки.

Это полезно для exec, потому что вы можете циклически обрабатывать каждое соответствие:

 var myRegex = /o/g;
 var myString = "fooo";
 for (var match; match = myRegex.exec(myString);) {
   alert(match + " at " + myRegex.lastIndex);
 }

но, очевидно, это не так полезно для test.

Ответ 2

Обычно выбирается тест, чтобы проверить, совпадает ли какой-либо шаблон, но глобальный флаг позволяет вам перебирать строку для подсчета совпадений или, подобно exec, делать что-то с каждым lastIndex. Другое использование - установить lastIndex из rx непосредственно перед тем, как тест будет сформирован, чтобы игнорировать совпадения перед некоторым символьным индексом.

var count=0, rx=/\s+/g, rx.lastIndex=100;
while(rx.test(string))count++;