Почему Javascript regex.lastIndex ведет себя по-разному для разных выражений регулярных выражений? - PullRequest
0 голосов
/ 16 апреля 2020
let text = "Hamilton is a musical with music, lyrics Book "
let regex = /\s/g

while((result = regex.exec(text)) != null) {
    console.log('idx:' + regex.lastIndex);
}

Значение regex.lastIndex на каждой итерации увеличивается и сохраняется в вызовах regex.exe c ().

Теперь, если я изменю строку:

let regex = /\s/g

to:

let regex = /\b/g

l oop никогда не остановится, а regex.lastIndex всегда будет 1.

Почему это работает для "\ s" (пробельные символы ) а не для \ b (границы слова)?

Исходная версия скрипта соответствует документации exe c () :

JavaScript Объекты RegExp сохраняют состояние, когда у них установлены глобальные или липкие флаги (например, / foo / g или / foo / y). Они хранят lastIndex из предыдущего матча. Используя это внутренне, exe c () можно использовать для итерации по нескольким совпадениям в текстовой строке

Версия после изменения не соответствует стандарту. Это ошибка?

1 Ответ

2 голосов
/ 16 апреля 2020

Согласно прочитанной вами документации, lastIndex начинается с 0 и изменяется на exec до последнего индекса первого найденного соответствия после lastIndex.

первый матч? Ну, это совпадение с нулевой шириной в начале строки. Это граница слова, не так ли? Это начало слова Hamilton. Какой последний индекс этого матча? Все же 0!

Так что lastIndex не действительно изменилось. На следующей итерации l oop происходит то же самое. Такое же совпадение найдено, потому что lastIndex по-прежнему равно 0. Сравните это с ситуацией, когда у вас есть совпадение не нулевой ширины, например \s. В этом случае вторая итерация l oop фактически найдет второе совпадение, потому что lastIndex равно увеличено на exec.

Если вы посмотрите на код, который regex101.com генерирует, в частности, есть механизмы, чтобы избежать этого бесконечного l oop:

const regex = /\b/gm;
const str = `Hamilton is a musical with music, lyrics Book `;
let m;

while ((m = regex.exec(str)) !== null) {
    // This is necessary to avoid infinite loops with zero-width matches
    if (m.index === regex.lastIndex) {
        regex.lastIndex++;
    }
    
    // The result can be accessed through the `m`-variable.
    m.forEach((match, groupIndex) => {
        console.log(`Found match, group ${groupIndex}: ${match}`);
    });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...