RegExp: lastIndex
Базовая поддержка Широко доступно
Эта возможность хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна во всех браузерах с июля 2015 года.
Свойство данных lastIndex экземпляра RegExp указывает индекс, с которого начинается следующий поиск совпадения.
Попробуйте это
const regex = /foo/g; const str = "table football, foosball"; regex.test(str); console.log(regex.lastIndex); // Expected output: 9 regex.test(str); console.log(regex.lastIndex); // Expected output: 19
Значение
Неотрицательное целое число.
Атрибуты свойства RegExp: lastIndex
| |
|---|---|
| Изменяемое | да |
| Перечисляемое | нет |
| Конфигурируемое | нет |
Описание
Это свойство устанавливается, только если экземпляр регулярного выражения использовал флаг g для указания глобального поиска или флаг y для указания "липкого" поиска. При вызове exec() для заданного ввода применяются следующие правила:
- Если
lastIndexпревышает длину ввода,exec()не найдет совпадения, иlastIndexбудет установлено в 0. - Если
lastIndexравно или меньше длины ввода,exec()попытается найти совпадение во вводе, начиная сlastIndex.- Если
exec()находит совпадение, тоlastIndexбудет установлено в позицию окончания совпадающей строки во вводе. - Если
exec()не находит совпадения, тоlastIndexбудет установлено в 0.
- Если
Другие методы, связанные с регулярными выражениями, такие как RegExp.prototype.test(), String.prototype.match(), String.prototype.replace() и т.д., вызывают exec() внутри, поэтому они по-разному влияют на lastIndex. См. их соответствующие страницы для получения подробной информации.
Примеры
Использование lastIndex
Рассмотрим следующую последовательность операторов:
const re = /(hi)?/g;
Совпадает с пустой строкой.
console.log(re.exec("hi"));
console.log(re.lastIndex);
Возвращает ["hi", "hi"], где lastIndex равно 2.
console.log(re.exec("hi"));
console.log(re.lastIndex);
Возвращает ["", undefined] — пустой массив, нулевой элемент которого является совпадающей строкой. В данном случае это пустая строка, поскольку lastIndex было равно 2 (и по-прежнему равно 2), а hi имеет длину 2.
Использование lastIndex с "липкими" регулярными выражениями
Свойство lastIndex является изменяемым (записываемым). Вы можете установить его, чтобы регулярное выражение начало следующий поиск с заданного индекса.
Флаг y почти всегда требует установки lastIndex. Он всегда выполняет строгое совпадение в lastIndex и не пытается искать совпадения в более поздних позициях. Это обычно полезно для написания парсеров, когда требуется найти совпадение токенов только в текущей позиции.
const stringPattern = /"[^"]*"/y; const input = `const message = "Hello world";`; stringPattern.lastIndex = 6; console.log(stringPattern.exec(input)); // null stringPattern.lastIndex = 16; console.log(stringPattern.exec(input)); // ['"Hello world"']
Перемотка lastIndex
Флаг g также выигрывает от установки lastIndex. Один из распространенных вариантов использования — когда строка изменяется в середине глобального поиска. В этом случае мы можем пропустить определенное совпадение, если строка укорачивается. Этого можно избежать путем "перемотки" (возврата) lastIndex.
const mdLinkPattern = /\[[^[\]]+\]\((?<link>[^()\s]+)\)/dg;
function resolveMDLink(line) {
let match;
let modifiedLine = line;
while ((match = mdLinkPattern.exec(modifiedLine))) {
const originalLink = match.groups.link;
const resolvedLink = originalLink.replaceAll(/^files|\/index\.md$/g, "");
modifiedLine =
modifiedLine.slice(0, match.indices.groups.link[0]) +
resolvedLink +
modifiedLine.slice(match.indices.groups.link[1]);
// Rewind the pattern to the end of the resolved link
mdLinkPattern.lastIndex += resolvedLink.length - originalLink.length;
}
return modifiedLine;
}
console.log(
resolveMDLink(
"[`lastIndex`](files/en-us/web/javascript/reference/global_objects/regexp/lastindex/index.md)",
),
); // [`lastIndex`](/en-us/web/javascript/reference/global_objects/regexp/lastindex)
console.log(
resolveMDLink(
"[`ServiceWorker`](files/en-us/web/api/serviceworker/index.md) and [`SharedWorker`](files/en-us/web/api/sharedworker/index.md)",
),
); // [`ServiceWorker`](/en-us/web/api/serviceworker) and [`SharedWorker`](/en-us/web/api/sharedworker)
Попробуйте удалить строку mdLinkPattern.lastIndex += resolvedLink.length - originalLink.length и запустить второй пример. Вы обнаружите, что вторая ссылка заменена неправильно, потому что lastIndex уже находится за индексом ссылки после того, как строка была укорочена.
Внимание: Этот пример предназначен только для демонстрации. Для работы с Markdown вам, вероятно, следует использовать библиотеку парсинга, а не регулярные выражения.
Оптимизация поиска
Вы можете оптимизировать поиск, установив lastIndex в точку, где предыдущие возможные вхождения могут быть проигнорированы. Например, вместо этого:
const stringPattern = /"[^"]*"/g; const input = `const message = "Hello " + "world";`; // Pretend we've already dealt with the previous parts of the string let offset = 26; const remainingInput = input.slice(offset); const nextString = stringPattern.exec(remainingInput); console.log(nextString[0]); // "world" offset += nextString.index + nextString.length;
Рассмотрите это:
stringPattern.lastIndex = offset; const nextString = stringPattern.exec(remainingInput); console.log(nextString[0]); // "world" offset = stringPattern.lastIndex;
Это потенциально более производительно, поскольку мы избегаем нарезки строк.
Избегание побочных эффектов
Побочные эффекты, вызванные exec(), могут сбивать с толку, особенно если входные данные разные для каждого exec().
const re = /foo/g;
console.log(re.test("foo bar")); // true
console.log(re.test("foo baz")); // false, because lastIndex is non-zero
Это еще больше сбивает с толку, когда вы вручную изменяете lastIndex. Чтобы локализовать побочные эффекты, не забывайте сбрасывать lastIndex после полной обработки каждого ввода.
const re = /foo/g;
console.log(re.test("foo bar")); // true
re.lastIndex = 0;
console.log(re.test("foo baz")); // true
С помощью некоторой абстракции вы можете потребовать, чтобы lastIndex было установлено в определенное значение перед каждым вызовом exec().
function createMatcher(pattern) {
// Create a copy, so that the original regex is never updated
const regex = new RegExp(pattern, "g");
return (input, offset) => {
regex.lastIndex = offset;
return regex.exec(input);
};
}
const matchFoo = createMatcher(/foo/);
console.log(matchFoo("foo bar", 0)[0]); // "foo"
console.log(matchFoo("foo baz", 0)[0]); // "foo"
Спецификации
Совместимость с браузерами
| Десктопные | Мобильные | Серверные | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox for Android | Opera Android | Safari on iOS | Samsung Internet | WebView Android | WebView on iOS | Bun | Deno | Node.js | |
lastIndex |
1 |
12 |
1 |
5 |
1 |
18 |
4 |
10.1 |
1 |
1.0 |
4.4 |
1 |
1.0.0 |
1.0 |
0.10.0 |
См. также
RegExp.prototype.dotAllRegExp.prototype.globalRegExp.prototype.hasIndicesRegExp.prototype.ignoreCaseRegExp.prototype.multilineRegExp.prototype.sourceRegExp.prototype.stickyRegExp.prototype.unicode
© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex