正则表达式:lastIndex
RegExp
实例的 lastIndex
数据属性指定开始下一个匹配的索引。
¥The lastIndex
data property of a RegExp
instance specifies the index at which to start the next match.
Try it
值
描述
¥Description
仅当正则表达式实例使用 g
标志指示全局搜索或使用 y
标志指示粘性搜索时,才设置此属性。当对给定输入调用 exec()
时,适用以下规则:
¥This property is set only if the regular expression instance used the g
flag to indicate a global search, or the y
flag to indicate a sticky search. The following rules apply when exec()
is called on a given input:
- 如果
lastIndex
大于输入的长度,则exec()
将找不到匹配项,并且lastIndex
将设置为 0。 - 如果
lastIndex
等于或小于输入的长度,exec()
将尝试匹配从lastIndex
开始的输入。- 如果
exec()
找到匹配项,则lastIndex
将设置为输入中匹配字符串末尾的位置。 - 如果
exec()
未找到匹配项,则lastIndex
将设置为 0。
- 如果
其他与正则表达式相关的方法,例如 RegExp.prototype.test()
、String.prototype.match()
、String.prototype.replace()
等,在幕后调用 exec()
,因此它们对 lastIndex
有不同的影响。有关详细信息,请参阅各自的页面。
¥Other regex-related methods, such as RegExp.prototype.test()
, String.prototype.match()
, String.prototype.replace()
, etc., call exec()
under the hood, so they have different effects on lastIndex
. See their respective pages for details.
示例
使用最后一个索引
¥Using lastIndex
考虑以下语句序列:
¥Consider the following sequence of statements:
const re = /(hi)?/g;
匹配空字符串。
¥Matches the empty string.
console.log(re.exec("hi"));
console.log(re.lastIndex);
返回 ["hi", "hi"]
,lastIndex
等于 2。
¥Returns ["hi", "hi"]
with lastIndex
equal to 2.
console.log(re.exec("hi"));
console.log(re.lastIndex);
返回 ["", undefined]
,一个空数组,其第 0 个元素是匹配字符串。在本例中,空字符串是因为 lastIndex
是 2(现在仍然是 2),而 hi
的长度为 2。
¥Returns ["", undefined]
, an empty array whose zeroth element is the match string. In this case, the empty string because lastIndex
was 2 (and still is 2) and hi
has length 2.
将 lastIndex 与粘性正则表达式一起使用
¥Using lastIndex with sticky regexes
lastIndex
属性是可写的。你可以将其设置为使正则表达式在给定索引处开始下一次搜索。
¥The lastIndex
property is writable. You can set it to make the regex start its next search at a given index.
y
标志几乎总是需要设置 lastIndex
。它始终严格匹配 lastIndex
并且不会尝试任何后面的位置。当你只想在当前位置匹配标记时,这通常对于编写解析器很有用。
¥The y
flag almost always requires setting lastIndex
. It always matches strictly at lastIndex
and does not attempt any later positions. This is usually useful for writing parsers, when you want to match tokens only at the current position.
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"']
倒回最后一个索引
¥Rewinding lastIndex
g
标志也受益于设置 lastIndex
。一种常见的用例是在全局搜索过程中修改字符串。在这种情况下,如果字符串被缩短,我们可能会遗漏特定的匹配。我们可以通过倒回 lastIndex
来避免这种情况。
¥The g
flag also benefits from setting lastIndex
. One common use case is when the string is modified in the middle of a global search. In this case, we may miss a particular match if the string is shortened. We can avoid this by rewinding 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
已经超过了链接的索引。
¥Try deleting the mdLinkPattern.lastIndex += resolvedLink.length - originalLink.length
line and running the second example. You will find that the second link is not replaced correctly, because the lastIndex
is already past the link's index after the string is shortened.
警告:该示例仅用于演示。要处理 Markdown,你可能应该使用解析库而不是正则表达式。
¥Warning: This example is for demonstration only. To deal with Markdown, you should probably use a parsing library instead of regex.
优化搜索
¥Optimizing searching
你可以通过将 lastIndex
设置为可以忽略先前可能出现的情况来优化搜索。例如,代替这个:
¥You can optimize searching by setting lastIndex
to a point where previous possible occurrences can be ignored. For example, instead of this:
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;
考虑一下:
¥Consider this:
stringPattern.lastIndex = offset;
const nextString = stringPattern.exec(remainingInput);
console.log(nextString[0]); // "world"
offset = stringPattern.lastIndex;
这可能会提高性能,因为我们避免了字符串切片。
¥This is potentially more performant because we avoid string slicing.
避免副作用
¥Avoiding side effects
exec()
引起的副作用可能会令人困惑,特别是如果每个 exec()
的输入都不同。
¥The side effects caused by exec()
can be confusing, especially if the input is different for each 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
。
¥This is even more confusing when you are hand-modifying lastIndex
. To contain the side effects, remember to reset lastIndex
after each input is completely processed.
const re = /foo/g;
console.log(re.test("foo bar")); // true
re.lastIndex = 0;
console.log(re.test("foo baz")); // true
通过一些抽象,你可以要求在每次 exec()
调用之前将 lastIndex
设置为特定值。
¥With some abstraction, you can require lastIndex
to be set to a particular value before each exec()
call.
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"
规范
Specification |
---|
ECMAScript Language Specification # sec-properties-of-regexp-instances |
浏览器兼容性
BCD tables only load in the browser