lastIndex
属性
exec
方法同样没提供方便的方法来指定字符串中的起始匹配位置。但我们可以使用一种比较麻烦的方法来实现该功能。
正则表达式对象包含了一些属性。其中一个属性是source
,该属性包含用于创建正则表达式的字符串。另一个属性是lastIndex
,可以在极少数情况下控制下一次匹配的起始位置。
所谓的极少数情况,指的是当正则表达式启用了全局(g
)或者粘性(y
),并且使用exec
匹配模式的时候。此外,另一个解决方案应该是向exec
传递的额外参数,但 JavaScript 的正则表达式接口能设计得如此合理才是怪事。
let pattern = /y/g;
pattern.lastIndex = 3;
let match = pattern.exec("xyzzy");
console.log(match.index);
// → 4
console.log(pattern.lastIndex);
// → 5
如果成功匹配模式,exec
调用会自动更新lastIndex
属性,来指向匹配字符串后的位置。如果无法匹配,会将lastIndex
清零(就像新构建的正则表达式对象lastIndex
属性为零一样)。
全局和粘性选项之间的区别在于,启用粘性时,仅当匹配直接从lastIndex
开始时,搜索才会成功,而全局搜索中,它会搜索匹配可能起始的所有位置。
let global = /abc/g;
console.log(global.exec("xyz abc"));
// → ["abc"]
let sticky = /abc/y;
console.log(sticky.exec("xyz abc"));
// → null
对多个exec
调用使用共享的正则表达式值时,这些lastIndex
属性的自动更新可能会导致问题。 你的正则表达式可能意外地在之前的调用留下的索引处开始。
let digit = /\d/g;
console.log(digit.exec("here it is: 1"));
// → ["1"]
console.log(digit.exec("and now: 1"));
// → null
全局选项还有一个值得深思的效果,它会改变match
匹配字符串的工作方式。如果调用match
时使用了全局表达式,不像exec
返回的数组,match
会找出所有匹配模式的字符串,并返回一个包含所有匹配字符串的数组。
console.log("Banana".match(/an/g));
// → ["an", "an"]
因此使用全局正则表达式时需要倍加小心。只有以下几种情况中,你确实需要全局表达式即调用replace
方法时,或是需要显示使用lastIndex
时。这也基本是全局表达式唯一的应用场景了。