为什么带有全局标志的 RegExp 会给出错误的结果? [英] Why does a RegExp with global flag give wrong results?

查看:36
本文介绍了为什么带有全局标志的 RegExp 会给出错误的结果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

<小时>

var reg =/^a$/g;for(i = 0; i++ <10;)console.log(reg.test("a"));

解决方案

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

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

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

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

<块引用>

RegExp.prototype.exec(string)

执行字符串的正则表达式匹配反对正则表达式和返回一个包含匹配结果,如果字符串不匹配 字符串ToString(string) 被搜索一个正则表达式的出现模式如下:

<块引用>

  1. R 成为这个 RexExp 对象.
  2. S 成为 ToString(string) 的值.
  3. lengthS 的长度.
  4. 让 lastIndex 是 R 上的 lastIndex 属性的值.
  5. 让 i 成为 ToInteger(lastIndex) 的值.
  6. 如果全局属性为假,让 i = 0.
  7. 如果我<0 或 i >length 然后将 RlastIndex 属性设置为 0 并返回 null.
  8. 调用 [[Match]],给它参数 S 和 i.如果 [[匹配]]返回失败,转步骤9;否则让 r 是它的状态结果并转到步骤 10.
  9. 让 i = i+1.
  10. 转到第 7 步.
  11. 让 e 成为 r 的 endIndex 值.
  12. 如果全局属性为true,将RlastIndex属性设置为e.
  13. 令 n 为 r 的捕获数组的长度.(这个是一样的值为 15.10.2.1'sNCapturingParens.)
  14. 返回具有以下属性的新数组:

  • 索引属性设置为完整的匹配子串字符串 S.
  • 输入属性已设置到 S.
  • 长度属性设置为n + 1.
  • 0 属性设置为匹配的子串(即S 之间的偏移量 i 包括在内偏移 e 独占).
  • 对于每个整数 i 使得 i >0 且 i ≤ n,将名为 ToString(i) 的属性设置为r 的 captures 数组的第 i 个元素.

What is the problem with this regular expression when I use the global flag and the case insensitive flag? Query is a user generated input. The result should be [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"));

解决方案

A RegExp object with the g flag keeps track of the lastIndex where a match occurred, so on subsequent matches it will start from the last used index, instead of 0. Take a look:

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

If you don't want to manually reset lastIndex to 0 after every test, just remove the g flag.

Here's the algorithm that the specs dictate (section 15.10.6.2):

RegExp.prototype.exec(string)

Performs a regular expression match of string against the regular expression and returns an Array object containing the results of the match, or null if the string did not match The string ToString(string) is searched for an occurrence of the regular expression pattern as follows:

  1. Let R be this RexExp object.
  2. Let S be the value of ToString(string).
  3. Let length be the length of S.
  4. Let lastIndex be the value of the lastIndex property on R.
  5. Let i be the value of ToInteger(lastIndex).
  6. If the global property is false, let i = 0.
  7. If i < 0 or i > length then set the lastIndex property of R to 0 and return null.
  8. Call [[Match]], giving it the arguments S and i. If [[Match]] returned failure, go to step 9; otherwise let r be its State result and go to step 10.
  9. Let i = i+1.
  10. Go to step 7.
  11. Let e be r's endIndex value.
  12. If the global property is true, set the lastIndex property of R to e.
  13. Let n be the length of r's captures array. (This is the same value as 15.10.2.1's NCapturingParens.)
  14. Return a new array with the following properties:

  • The index property is set to the position of the matched substring within the complete string S.
  • The input property is set to S.
  • The length property is set to n + 1.
  • The 0 property is set to the matched substring (i.e. the portion of S between offset i inclusive and offset e exclusive).
  • For each integer i such that i > 0 and i ≤ n, set the property named ToString(i) to the ith element of r's captures array.

这篇关于为什么带有全局标志的 RegExp 会给出错误的结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆