为什么带有全局标志的RegExp会给出错误的结果?
当我使用全局标志和不区分大小写的标志时,这个正则expression式有什么问题? 查询是用户生成的input。 结果应该是[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"));
RegExp
对象跟踪发生匹配的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'));
如果您不想在每次testing后手动将lastIndex
重置为0,只需删除g
标志。
以下是规范规定的algorithm(第15.10.6.2节):
RegExp.prototype.exec(串)
对正则expression式执行string的正则expression式匹配,并返回包含匹配结果的Array对象;如果string不匹配,则返回null如下所示searchstringToString(string)以查找正则expression式模式:
- 设S是ToString(string)的值。
- 设长度为S的长度
- 让lastIndex是lastIndex属性的值。
- 让我成为ToInteger(lastIndex)的值。
- 如果全局属性是假的,让我= 0。
- 如果我<0或I>长度然后设置lastIndex为0,并返回null。
- 调用[[Match]],给它参数S和i。 如果[[Match]]返回失败,请转至步骤8; 否则让r为其状态结果并转到步骤10。
- 让我=我+ 1。
- 转到第6步。
- 设e是r的endIndex值。
- 如果全局属性为true,则将lastIndex设置为e。
- 设n是r的捕获数组的长度。 (这与15.10.2.1的NCapturingParens相同。)
- 返回具有以下属性的新数组:
- index属性被设置为完整stringS中的匹配子string的位置。
- input属性设置为S.
- 长度属性设置为n + 1。
- 0属性被设置为匹配的子string(即,在偏移i包含和偏移e独占之间的S的部分)。
- 对于I> 0和I≤n的每个整数i,将名为ToString(i)的属性设置为r的capture数组的第i个元素。
您正在使用一个RegExp
对象并多次执行它。 在每个连续的执行过程中,从最后一个匹配索引继续。
您需要“重置”正则expression式,从每个执行开始之前开始:
result.push(re.test('Foo Bar')); re.lastIndex = 0; result.push(re.test('Foo Bar')); // result is now [true, true]
话虽如此,每次创build一个新的RegExp对象可能会更具可读性(因为无论如何cachingRegExp,开销最小):
result.push((/Foo B/gi).test(stringA)); result.push((/Foo B/gi).test(stringB));
RegExp.prototype.test
更新正则expression式的lastIndex
属性,以便每个testing将从最后一个停止的地方开始。 我build议使用String.prototype.match
因为它不会更新lastIndex
属性:
!!'Foo Bar'.match(re); // -> true !!'Foo Bar'.match(re); // -> true
注意!!
将其转换为布尔值,然后反转布尔值,以反映结果。
或者,您可以重置lastIndex
属性:
result.push(re.test('Foo Bar')); re.lastIndex = 0; result.push(re.test('Foo Bar'));
删除全球克旗将解决您的问题。
var re = new RegExp(query, 'gi');
应该
var re = new RegExp(query, 'i');
使用/ g标志告诉它在命中后继续search。
如果匹配成功,则exec()方法将返回一个数组并更新正则expression式对象的属性。
在你第一次search之前:
myRegex.lastIndex //is 0
第一次search后
myRegex.lastIndex //is 8
删除g,并在每次调用exec()后退出search。