Spec-Zone.ru › JavaScript

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"

Спецификации

Спецификация
ECMAScript® 2027 Language Specification
# sec-properties-of-regexp-instances

Совместимость с браузерами

Десктопные Мобильные Серверные
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.dotAll
  • RegExp.prototype.global
  • RegExp.prototype.hasIndices
  • RegExp.prototype.ignoreCase
  • RegExp.prototype.multiline
  • RegExp.prototype.source
  • RegExp.prototype.sticky
  • RegExp.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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API