使用Regex匹配的奇怪行为[重复]

时间:2022-05-03 17:24:05

This question already has an answer here:

这个问题已经有了答案:

Here is a Codepen version.

这是一个代码页版本。

My goal is to iterate over the elements of an array, search for a regex matching ~@something@~, remove those "bookends" identifying the match, then .join() the array. In the following example, the result should look like a/b/c.

我的目标是遍历数组的元素,搜索regex匹配~@something@~,删除标识匹配的“bookends”,然后删除.join()数组。在下面的示例中,结果应该类似于a/b/c。

However instead, I get the result a/~@b@~/c. To make things even more confusing, when I reverse the order of the array elements, the problem result changes from the ~@b@~ to the ~@c@~. And, finally, to make things downright weird, the problem seems to resolve itself by adding a simple test method which, itself, always returns a value of false. See comments for those in code. And see for yourself.

但是,我得到的结果是a/~@b@~/c。更让人困惑的是,当我反转数组元素的顺序时,问题的结果从~@b@~变成~@c@~。最后,为了让事情变得完全怪异,问题似乎是通过添加一个简单的测试方法来解决的,这个方法本身总是返回一个false值。请参阅代码中的注释。看看你自己。

What is causing this strange behavior? And what is the correct way to iterate over these elements and do the substitution I describe?

是什么导致了这种奇怪的行为?迭代这些元素并做我描述的替换的正确方法是什么?

function myFunction() {
  var a = ["a", "~@b@~", "~@c@~"]
  var re = /~@(.*?)@~/g;
  var i = a.length;
  //  Uncomment below line to see the problem change from ~@b@~ to ~@c@~
  //a.reverse();
  while (i--) {
    console.log('i', i, 'str', a[i]);
    var match = re.exec(a[i]);
    console.log('match', match);
    // Uncomment the below line to see it work properly.
    //console.log('test', re.test(a[i]));
    if (match && match[0] && match[1]) {
      a[i] = a[i].replace(match[0], match[1]);
      console.log('a[i]', a[i]);
    }
  }
  var res = a.join('/');
  document.getElementById("demo").innerHTML = res;
}
<p>
  My goal is to print the string: <code>a/b/c</code>. See weird <i>uncomment</i> fix in JS.
  <button onclick="myFunction()">Click Here</button>
</p>
<p id="demo"></p>

2 个解决方案

#1


2  

The reason for the behavior is that your regex has the global flag (g) but you're only executing it once; that means its lastIndex is set and the next time you run it, it tries to start from where it left off.

这种行为的原因是您的regex有全局标志(g),但是您只执行一次;这意味着设置了它的lastIndex,下次运行它时,它试图从它停止的地方开始。

Either remove the g flag, or add

要么删除g标志,要么添加。

re.lastIndex = -1;

...as the first line in the while loop:

…作为while循环的第一行:

function myFunction() {
  var a = ["a", "~@b@~", "~@c@~"]
  var re = /~@(.*?)@~/;             // <=== Note `g` removed
  var i = a.length;
  var t;
  while (i--) {
    var match = re.exec(a[i]);
    if (match && match[0] && match[1]) {
      a[i] = a[i].replace(match[0], match[1]);
    }
  }
  var res = a.join('/');
  document.getElementById("demo").innerHTML = res;
}
<p>
  My goal is to print the string: <code>a/b/c</code>. See weird <i>uncomment</i> fix in JS.
  <button onclick="myFunction()">Click Here</button>
</p>
<p id="demo"></p>

However, if you leave that g flag on the regex, you can replace the entire contents of the while loop with

但是,如果在regex中保留g标志,则可以将while循环的全部内容替换为

a[i] = a[i].replace(re, "$1");

function myFunction() {
  var a = ["a", "~@b@~", "~@c@~"]
  var re = /~@(.*?)@~/;
  var i = a.length;
  var t;
  //  Uncomment below line to see the problem change from ~@b@~ to ~@c@~
  //a.reverse();
  while (i--) {
    a[i] = a[i].replace(re, "$1");
  }
  var res = a.join('/');
  document.getElementById("demo").innerHTML = res;
}
<p>
  My goal is to print the string: <code>a/b/c</code>. See weird <i>uncomment</i> fix in JS.
  <button onclick="myFunction()">Click Here</button>
</p>
<p id="demo"></p>

...which also has the advantage of handling entries in the form "~@b@~~@c@~" (because it replaces all occurrences in the string, not just the first one).

…它还具有处理形式为“~@b@~~@c@~”的条目的优势(因为它替换了字符串中的所有事件,而不仅仅是第一个)。

#2


1  

Removing the global flag from the regex to change from:

从正则表达式中移除全局标志以更改:

var re = /~@(.*?)@~/g;

to:

:

var re = /~@(.*?)@~/;

should fix this.

应该解决这个问题。

#1


2  

The reason for the behavior is that your regex has the global flag (g) but you're only executing it once; that means its lastIndex is set and the next time you run it, it tries to start from where it left off.

这种行为的原因是您的regex有全局标志(g),但是您只执行一次;这意味着设置了它的lastIndex,下次运行它时,它试图从它停止的地方开始。

Either remove the g flag, or add

要么删除g标志,要么添加。

re.lastIndex = -1;

...as the first line in the while loop:

…作为while循环的第一行:

function myFunction() {
  var a = ["a", "~@b@~", "~@c@~"]
  var re = /~@(.*?)@~/;             // <=== Note `g` removed
  var i = a.length;
  var t;
  while (i--) {
    var match = re.exec(a[i]);
    if (match && match[0] && match[1]) {
      a[i] = a[i].replace(match[0], match[1]);
    }
  }
  var res = a.join('/');
  document.getElementById("demo").innerHTML = res;
}
<p>
  My goal is to print the string: <code>a/b/c</code>. See weird <i>uncomment</i> fix in JS.
  <button onclick="myFunction()">Click Here</button>
</p>
<p id="demo"></p>

However, if you leave that g flag on the regex, you can replace the entire contents of the while loop with

但是,如果在regex中保留g标志,则可以将while循环的全部内容替换为

a[i] = a[i].replace(re, "$1");

function myFunction() {
  var a = ["a", "~@b@~", "~@c@~"]
  var re = /~@(.*?)@~/;
  var i = a.length;
  var t;
  //  Uncomment below line to see the problem change from ~@b@~ to ~@c@~
  //a.reverse();
  while (i--) {
    a[i] = a[i].replace(re, "$1");
  }
  var res = a.join('/');
  document.getElementById("demo").innerHTML = res;
}
<p>
  My goal is to print the string: <code>a/b/c</code>. See weird <i>uncomment</i> fix in JS.
  <button onclick="myFunction()">Click Here</button>
</p>
<p id="demo"></p>

...which also has the advantage of handling entries in the form "~@b@~~@c@~" (because it replaces all occurrences in the string, not just the first one).

…它还具有处理形式为“~@b@~~@c@~”的条目的优势(因为它替换了字符串中的所有事件,而不仅仅是第一个)。

#2


1  

Removing the global flag from the regex to change from:

从正则表达式中移除全局标志以更改:

var re = /~@(.*?)@~/g;

to:

:

var re = /~@(.*?)@~/;

should fix this.

应该解决这个问题。