当我使用全局标志和不区分大小写的标志时,这个正则表达式有什么问题?查询是用户生成的输入。结果应该是[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"));
答案 0 :(得分:299)
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'));
如果您不想在每次测试后手动将lastIndex
重置为0,只需删除g
标记。
这是规范规定的算法(第15.10.6.2节):
<强> RegExp.prototype.exec(字符串)强>
执行 字符串的正则表达式匹配 反对正则表达和 返回一个包含的Array对象 匹配的结果,如果是,则为null 字符串不匹配字符串 搜索ToString(字符串) 正则表达式的出现 模式如下:
- 设S为ToString(string)的值。
- 设长度为S的长度。
- 让lastIndex为lastIndex属性的值。
- 让我成为ToInteger(lastIndex)的值。
- 如果全局属性为false,则让i = 0。
- 如果我&lt; 0或I&gt;然后将lastIndex设置为0并返回null。
- 调用[[Match]],给它参数S和i。如果[[匹配]] 返回失败,转到第8步; 否则让r成为州的结果 并转到第10步。
- 设i = i + 1。
- 转到第6步。
- 设e为r的endIndex值。
- 如果global属性为true,请将lastIndex设置为e。
- 设n为r的捕获数组的长度。 (这是一样的 值为15.10.2.1 NCapturingParens。)
- 返回具有以下属性的新数组:
醇>
- 指数 属性设置为的位置 完整的匹配子串 string S。
- 设置输入属性 到S。
- length属性设置为 n + 1。
- 0属性设置为 匹配的子串(即。的一部分) S在offset i包含和之间 抵消e独家)。
- 每个人 整数i使得I> 0和I≤n, 将名为ToString(i)的属性设置为 r的第i个元素捕获数组。
答案 1 :(得分:65)
您正在使用单个RegExp
对象并多次执行它。在每次连续执行时,它从最后一个匹配索引继续。
您需要“重置”正则表达式,以便在每次执行之前从头开始:
result.push(re.test('Foo Bar'));
re.lastIndex = 0;
result.push(re.test('Foo Bar'));
// result is now [true, true]
说过每次创建一个新的RegExp对象可能更具可读性(因为RegExp无论如何都是缓存的,所以开销很小):
result.push((/Foo B/gi).test(stringA));
result.push((/Foo B/gi).test(stringB));
答案 2 :(得分:34)
RegExp.prototype.test
更新正则表达式的 lastIndex
属性,以便每个测试都会从最后一个测试停止的位置开始。我建议使用 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'));
答案 3 :(得分:9)
删除全局g
标记可以解决您的问题。
var re = new RegExp(query, 'gi');
应
var re = new RegExp(query, 'i');
答案 4 :(得分:0)
使用/ g标志告诉它在点击后继续搜索。
在您第一次搜索之前:
myRegex.lastIndex
//is 0
第一次搜索后
myRegex.lastIndex
//is 8
删除g并在每次调用exec()后退出搜索。
答案 5 :(得分:0)
我具有以下功能:
function parseDevName(name) {
var re = /^([^-]+)-([^-]+)-([^-]+)$/g;
var match = re.exec(name);
return match.slice(1,4);
}
var rv = parseDevName("BR-H-01");
rv = parseDevName("BR-H-01");
第一个呼叫有效。
第二个电话没有。 slice
操作抱怨为空值。我认为这是由于re.lastIndex
引起的。这很奇怪,因为我希望每次调用该函数时都会分配一个新的RegExp
,并且不会在函数的多次调用之间共享。
当我将其更改为:
var re = new RegExp('^([^-]+)-([^-]+)-([^-]+)$', 'g');
然后我没有得到lastIndex
保持效果。它的工作符合我的预期。
答案 6 :(得分:0)
您需要设置re.lastIndex = 0,因为使用g标志regex跟踪发生的最后一次匹配,因此测试不会去测试相同的字符串,因为您需要这样做re.lastIndex = 0
var query = 'Foo B';
var re = new RegExp(query, 'gi');
var result = [];
result.push(re.test('Foo Bar'));
re.lastIndex=0;
result.push(re.test('Foo Bar'));
console.log(result)