为什么相同的RegExp表现不同? [重复]

时间:2022-06-22 04:19:03

Possible Duplicate:
Interesting test of Javascript RegExp
Regular expression test can't decide between true and false (JavaScript)

可能重复:Javascript RegExp的有趣测试正则表达式测试无法在true和false之间做出决定(JavaScript)

Example of issue. When ran inline the results are as I would expect. But when stored as a variable it skips the middle span element.

问题的例子。在内联运行时,结果如我所料。但是当存储为变量时,它会跳过中间跨度元素。

// Inline RegExp
function getToggleClasses() {
  var toggler = [],
      elements = document.getElementsByTagName("*"),
      i=0,
      len = elements.length;

  for (i; i < len; i++) {
    if (/toggler/g.test(elements[i].className)) {
      toggler.push(elements[i]);
    }
  }

  document.getElementById('results').innerHTML += "<br />Inline: " + toggler.length;
}

// Variable
function getToggleClasses2() {
  var toggler = [],
      elements = document.getElementsByTagName("*"),
      tester = /toggler/g,
      i=0,
      len = elements.length;

  for (i; i < len; i++) {
    if (tester.test(elements[i].className)) {
      toggler.push(elements[i]);
    }
  }

  document.getElementById('results').innerHTML += "<br />Variable: " + toggler.length;
}
​

Mark up:

标记:

<span class="toggler">A</span>
<span class="toggler">B</span>
<span class="toggler">C</span>

Given: I understand there is no reason to use a RegExp to do this comparison and I also understand how great libraries such as jQuery are. I also know that the g is not needed in this case.

鉴于:我理解没有理由使用RegExp进行这种比较,我也理解jQuery这样的优秀库。我也知道在这种情况下不需要g。

I can't understand why these two methods should ever return different results.

我不明白为什么这两种方法应该返回不同的结果。

3 个解决方案

#1


9  

RegExp instances are stateful, so reusing them can cause unexpected behavior. In this particular case, it's because the instance is global, meaning:

RegExp实例是有状态的,因此重用它们可能会导致意外行为。在这种特殊情况下,这是因为实例是全局的,这意味着:

that the regular expression should be tested against all possible matches in a string.

应该针对字符串中的所有可能匹配来测试正则表达式。

That's not the only difference caused by using g, however. From RegExp.test @ MDN:

然而,这不是使用g引起的唯一差异。来自RegExp.test @ MDN:

As with exec (or in combination with it), test called multiple times on the same global regular expression instance will advance past the previous match.

与exec(或与其结合)一样,在同一个全局正则表达式实例上多次调用的测试将超过上一个匹配。


Remove the g flag, or set lastIndex to 0 (thanks, @zzzzBov).

删除g标志,或将lastIndex设置为0(谢谢,@ zzzonBov)。

#2


3  

/g is not needed and should not be used in this case.

/ g不是必需的,在这种情况下不应该使用。

The behavior differs in these cases because in the "inline" case the regex object is recreated each iteration of the loop. While in the variable is created once, and keeps its state (lastIndex) between loop iterations.

在这些情况下,行为不同,因为在“内联”情况下,每次循环迭代都会重新创建正则表达式对象。而在变量中创建一次,并在循环迭代之间保持其状态(lastIndex)。

Move the var into the loop and you will get the same result:

将var移动到循环中,您将得到相同的结果:

// Variable
function getToggleClasses2() {
  var toggler = [],
      elements = document.getElementsByTagName("*"),
      i=0,
      len = elements.length;

  for (i; i < len; i++) {
    var tester = /toggler/g;
    if (tester.test(elements[i].className)) {
      toggler.push(elements[i]);
    }
  }

  document.getElementById('results').innerHTML += "<br />Variable: " + toggler.length;
}

#3


1  

The regex maintains a variable called lastIndex, which is the index to start the next search. From MDN:

正则表达式维护一个名为lastIndex的变量,该变量是开始下一次搜索的索引。来自MDN:

As with exec (or in combination with it), test called multiple times on the same global regular expression instance will advance past the previous match.

与exec(或与其结合)一样,在同一个全局正则表达式实例上多次调用的测试将超过上一个匹配。

When you define an inline regex for each iteration, the state is lost and lastIndex is always 0 because you have a fresh regex each time. If you keep the regex in a veriable, the lastIndex is saved as the ending position of the last match, which in this case causes the next search for begin at the end of the next string, resulting in a failed match. When the third comparison comes around, the lastIndex has been reset to 0 because the regex knows it got no results last time.

为每次迭代定义内联正则表达式时,状态将丢失,lastIndex始终为0,因为每次都有一个新的正则表达式。如果将正则表达式保持在可靠状态,则lastIndex将保存为最后一个匹配的结束位置,在这种情况下会导致下一个字符串结束时的下一个搜索开始,从而导致匹配失败。当第三次比较到来时,lastIndex已被重置为0,因为正则表达式知道它上次没有结果。

#1


9  

RegExp instances are stateful, so reusing them can cause unexpected behavior. In this particular case, it's because the instance is global, meaning:

RegExp实例是有状态的,因此重用它们可能会导致意外行为。在这种特殊情况下,这是因为实例是全局的,这意味着:

that the regular expression should be tested against all possible matches in a string.

应该针对字符串中的所有可能匹配来测试正则表达式。

That's not the only difference caused by using g, however. From RegExp.test @ MDN:

然而,这不是使用g引起的唯一差异。来自RegExp.test @ MDN:

As with exec (or in combination with it), test called multiple times on the same global regular expression instance will advance past the previous match.

与exec(或与其结合)一样,在同一个全局正则表达式实例上多次调用的测试将超过上一个匹配。


Remove the g flag, or set lastIndex to 0 (thanks, @zzzzBov).

删除g标志,或将lastIndex设置为0(谢谢,@ zzzonBov)。

#2


3  

/g is not needed and should not be used in this case.

/ g不是必需的,在这种情况下不应该使用。

The behavior differs in these cases because in the "inline" case the regex object is recreated each iteration of the loop. While in the variable is created once, and keeps its state (lastIndex) between loop iterations.

在这些情况下,行为不同,因为在“内联”情况下,每次循环迭代都会重新创建正则表达式对象。而在变量中创建一次,并在循环迭代之间保持其状态(lastIndex)。

Move the var into the loop and you will get the same result:

将var移动到循环中,您将得到相同的结果:

// Variable
function getToggleClasses2() {
  var toggler = [],
      elements = document.getElementsByTagName("*"),
      i=0,
      len = elements.length;

  for (i; i < len; i++) {
    var tester = /toggler/g;
    if (tester.test(elements[i].className)) {
      toggler.push(elements[i]);
    }
  }

  document.getElementById('results').innerHTML += "<br />Variable: " + toggler.length;
}

#3


1  

The regex maintains a variable called lastIndex, which is the index to start the next search. From MDN:

正则表达式维护一个名为lastIndex的变量,该变量是开始下一次搜索的索引。来自MDN:

As with exec (or in combination with it), test called multiple times on the same global regular expression instance will advance past the previous match.

与exec(或与其结合)一样,在同一个全局正则表达式实例上多次调用的测试将超过上一个匹配。

When you define an inline regex for each iteration, the state is lost and lastIndex is always 0 because you have a fresh regex each time. If you keep the regex in a veriable, the lastIndex is saved as the ending position of the last match, which in this case causes the next search for begin at the end of the next string, resulting in a failed match. When the third comparison comes around, the lastIndex has been reset to 0 because the regex knows it got no results last time.

为每次迭代定义内联正则表达式时,状态将丢失,lastIndex始终为0,因为每次都有一个新的正则表达式。如果将正则表达式保持在可靠状态,则lastIndex将保存为最后一个匹配的结束位置,在这种情况下会导致下一个字符串结束时的下一个搜索开始,从而导致匹配失败。当第三次比较到来时,lastIndex已被重置为0,因为正则表达式知道它上次没有结果。