为什么带有全局标志的 RegExp 会给出错误的结果?

问题描述

RegExp带有标志的对象g会跟踪lastIndex匹配发生的位置,因此在后续匹配中,它将从最后使用的索引开始,而不是 0。看看:

var query = 'Foo B';
var re = new RegExp(query, 'gi');
var result = [];
result.push(re.test('Foo Bar'));

alert(re.lastIndex);

result.push(re.test('Foo Bar'));

如果您不想lastIndex在每次测试后手动重置为 0,只需删除g标志即可。

这是规范规定的算法(第 15.10.6.2 节):

对正则表达式执行字符串的正则表达式匹配,并返回一个包含匹配结果的 Array 对象,如果字符串不匹配,则返回 null 搜索字符串 ToS​​tring(string) 以查找正则表达式模式的出现,如下所示:

  1. R 成为这个 RexExp 对象。
  2. S 为 ToString(string) 的值。
  3. lengthS 的长度。
  4. 设 i 为 ToInteger(lastIndex) 的值。
  5. 如果全局属性为假,则令 i = 0。
  6. 如果 i < 0 或 i > 长度,则将 R的 lastIndex 属性设置为 0 并返回 null。 __
  7. 调用 [[Match]],给它参数 S 和 i。如果 [[Match]] 返回失败,则转到步骤 9;否则令 r 为其状态结果并转到步骤 10。
  8. 令 i = i+1。
  9. 转到步骤 7。
  10. 设 e 为 r 的 endindex 值。
  11. 令 n 为 r 的捕获数组的长度。(这与 15.10.2.1 的 NCCapturingParens 的值相同。)
  12. 返回具有以下属性的新数组:

  13. index 属性设置为完整字符串 S 中匹配子字符串的位置。

  14. 输入属性设置为 S。
  15. 长度属性设置为 n + 1。
  16. 0 属性设置为匹配的子字符串(即 S 的偏移量 i 包含和偏移量 e 不包含之间的部分)。
  17. 对于每个整数 i,使得 i > 0 并且 i≥ n,将名为 ToString(i) 的属性设置为 r 的捕获数组的第 i 个元素。

解决方法

当我使用全局标志和不区分大小写标志时,这个正则表达式有什么问题?查询是用户生成的输入。结果应该是 [true,true]。

var query = 'Foo B';
var re = new RegExp(query,'gi');
var result = [];
result.push(re.test('Foo Bar'));
result.push(re.test('Foo Bar'));
// result will be [true,false]

var reg = /^a$/g;

for(i = 0; i++ < 10;)

   console.log(reg.test("a"));