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

2020/10/07 06:01 · javascript ·  · 0评论

当我使用全局标志和不区分大小写的标志时,此正则表达式有什么问题?查询是用户生成的输入。结果应该是[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带有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节):

RegExp.prototype.exec(字符串)

与正则表达式执行字符串的正则表达式匹配,并返回包含匹配结果的Array对象;如果字符串不匹配,则返回null。在字符串ToString(string)中搜索正则表达式模式的出现,如下所示:

  1. R为该RexExp对象。
  2. S为ToString(string)的值。
  3. lengthS的长度
  4. 令lastIndex为R上的lastIndex属性的值
  5. 令我为ToInteger(lastIndex)的值。
  6. 如果全局属性为false,则让i = 0。
  7. 如果i <0或i> length,则将RlastIndex属性设置为0并返回null。
  8. 调用[[Match]],为其指定参数S和i。如果[[Match]]返回失败,请转到步骤9;否则,请执行步骤9。否则,将r设为其State结果并转到步骤10。
  9. 令i = i + 1。
  10. 转到步骤7。
  11. 令e为r的endIndex值。
  12. 如果global属性为true,则将RlastIndex属性设置为e。
  13. 令n为r的捕获数组的长度。(与15.10.2.1的NCapturingParens相同。)
  14. 返回具有以下属性的新数组:
  • index属性设置为匹配的字符串在完整字符串S中的位置。
  • 输入属性设置为S。
  • length属性设置为n + 1。
  • 0属性设置为匹配的子字符串(即,偏移量i包含在内和偏移量e排斥之间的S部分)。
  • 对于每个i> 0并且i≤n的整数i,将名为ToString(i)的属性设置为r的捕获数组的第i个元素。

您正在使用单个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));

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'));

删除全局g标志将解决您的问题。

var re = new RegExp(query, 'gi');

应该

var re = new RegExp(query, 'i');

使用/ g标志告诉它在命中后继续搜索。

如果匹配成功,则exec()方法返回一个数组并更新正则表达式对象的属性。

首次搜索之前:

myRegex.lastIndex
//is 0

第一次搜索后

myRegex.lastIndex
//is 8

删除g,并在每次调用exec()之后退出搜索。

您需要设置re.lastIndex = 0,因为使用g标志正则表达式跟踪发生的最后一次匹配,因此测试不会去测试同一字符串,因此您需要这样做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)

我有功能:

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保持效果。它按我期望的那样工作。

本文地址:http://javascript.askforanswer.com/weishenmedaiyouquanjubiaozhideregexpgeichucuowudejieguo.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!