Почему модификатор "g" дает разные результаты, когда test() вызывается дважды?
С учетом этого кода:
var reg = /a/g;
console.log(reg.test("a"));
console.log(reg.test("a"));
Получаю этот результат:
true
false
Я понятия не имею, как это может произойти. Я тестировал как в Node.js(v8), так и в браузере Firefox.
Ответ 1
Чтобы решить проблему, вы можете удалить флаг g или reset lastIndex, как в
var reg = /a/g;
console.log(reg.test("a"));
reg.lastIndex = 0;
console.log(reg.test("a"));
Проблема возникает из-за того, что test основывается на exec, который ищет больше совпадений после первого, если передается одна и та же строка, и присутствует флаг g.
Пусть совпадение будет результатом оценки алгоритма RegExp.prototype.exec (15.10.6.2) на этом объекте RegExp с использованием строки в качестве аргумента.
Если совпадение не null, верните true; else return false.
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++;