JS字符串仅替换每隔一次

JS string replace only replacing every other occurence

本文关键字:一次 字符串 替换 JS      更新时间:2023-09-26

我有以下JS:

"a a a a".replace(/(^|'s)a('s|$)/g, '$1')

我希望结果是'',但反而得到了'a a'.谁能向我解释我做错了什么?

澄清:我试图做的是删除所有被空格(即整个令牌)覆盖的'a'

这是因为这个正则表达式/(^|'s)a('s|$)/g将上一个字符和下一个字符匹配到每个

在字符串"a a a a"中,正则表达式匹配:

    "
  • a",那么要检查的字符串就变成了"a a"$(但现在字符串的开头不是开头,前面没有空格)
  • "a"(
  • 第三个a),然后变成"a"$(不匹配,因为前面没有空格)

编辑:有点棘手,但工作(没有正则表达式):

var a = "a a a a";
// Handle beginning case 'a '
var startI = a.indexOf("a ");
if (startI === 0){
    var off = a.charAt(startI + 2) !== "a" ? 2 : 1; // test if "a" come next to keep the space before
    a = a.slice(startI + off);
}
// Handle middle case ' a '
var iOf = -1;
while ((iOf = a.indexOf(" a ")) > -1){
    var off = a.charAt(iOf + 3) !== "a" ? 3 : 2; // same here
    a = a.slice(0, iOf) + a.slice(iOf+off, a.length);
}
// Handle end case ' a'
var endI = a.indexOf(" a");
if (endI === a.length - 2){
    a = a.slice(0, endI);
}
a; // ""

第一个"a"匹配。然后它将尝试与"a a"匹配,这将首先跳过a,然后匹配"a"。然后它将尝试与不匹配的"a"匹配。

  1. 第一个匹配项将替换为行首。 => '"^'"
  2. 然后我们有不匹配的"a"=>"a"
  3. 第二个匹配项将替换为"=>"
  4. 然后我们有不匹配的"a"=>"a"

结果将是"a"。

要获得所需的结果,您可以这样做:

"a a a a".replace(/(?:'s+a(?='s))+'s+|^a's+(?=[^a]|$|a'S)|^a|'s*a$/g, '')

正如其他人试图指出的那样,问题是正则表达式会消耗周围的空间作为匹配的一部分。这里有一个[希望]更直接的解释,说明为什么正则表达式不能按预期工作:

首先让我们分解正则表达式,它说匹配字符串的空格或开头,后跟一个"a",后跟一个空格或字符串的结尾。

现在让我们将其应用于字符串。我在字符串下面添加了字符索引,以便于谈论:

a a a a
0123456

正则表达式查看 0 索引字符,并在该位置找到一个"a",然后在索引 2 处找到一个空格。这是一个匹配项,因为它是字符串的开头,后跟一个 a 后跟一个空格。匹配的长度是 2('a' 和空格),所以我们使用两个字符并在索引 2 处开始下一次搜索。

字符 2 ('a') 既不是空格也不是字符串的开头,因此它与我们的正则表达式的开头不匹配,因此我们使用该字符(不替换它)并继续下一个字符。

字符 3 是一个空格,后跟

一个"a",后跟另一个空格,与我们的正则表达式匹配。我们用一个空字符串替换它,消耗匹配的长度(3 个字符 - "a"),然后继续索引 6。

字符 6 ('a') 既不是空格也不是字符串的开头,因此它与我们的正则表达式的开头不匹配,因此我们使用该字符(不替换它)并继续下一个字符。

现在我们到了字符串的末尾,所以我们完成了。

则表达式之所以@caeth建议(/(^|'s+)a(?='s|$)/g)起作用是因为?=量词。来自 MDN 正则表达式文档:

仅当 x 后跟 y 时才匹配 x。例如,/Jack(?=Sprat)/仅当"杰克"后跟"Sprat"时才匹配。 /Jack(?=Sprat|Frost)/仅当"Jack"后面跟着"Sprat"或"Frost"时,才会匹配它。但是,"鲱鱼"和"弗罗斯特"都不是比赛结果的一部分。

因此,在这种情况下,?=量词会检查以下字符是否为空格,而不实际使用该字符。

(^|'s)a(?='s|$)

试试这个。替换为 $1 。请参阅演示。

https://regex101.com/r/gQ3kS4/3

请改用这个:

"a a a a".replace(/(^|'s*)a('s|$)/g, '$1')

用"*"替换所有出现的"a"

问候

或者你可以把字符串拆分开来,过滤它,然后粘回去:

"a ba sl lf a df a a df r a".split(/'s+/).filter(function (x) { return x != "a" }).join(" ")
>>> "ba sl lf df df r"
"a a a a".split(/'s+/).filter(function (x) { return x != "a" }).join(" ")
>>> ""

或者在 ECMAScript 6 中:

"a ba sl lf a df a a df r a".split(/'s+/).filter(x => x != "a").join(" ")
>>> "ba sl lf df df r"
"a a a a".split(/'s+/).filter(x => x != "a").join(" ")
>>> ""

我假设没有前导空格和尾随空格。如果要删除假设,可以将筛选器更改为x && x != 'a'