JS字符串替换仅替换所有其他事件

时间:2014-12-23 21:32:26

标签: javascript regex

我有以下JS:

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

我希望结果为'',而是获得'a a'。谁能向我解释我做错了什么?

澄清:我要做的是删除所有出现的空格({1}}被空格包围(即整个令牌)

6 个答案:

答案 0 :(得分:2)

首先" a"火柴。 然后它将尝试匹配" a a&#34 ;,它将首先跳过a,然后匹配" a"。 然后它将尝试匹配" a",这将不匹配。

  1. 第一场比赛将被替换为第一场比赛。 => " ^"
  2. 然后我们有" a"没有匹配=> ""
  3. 第二场比赛将被替换为" " => " "
  4. 然后我们有" a"没有匹配=> ""
  5. 结果将是" a"。

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

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

答案 1 :(得分:2)

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

字符串"a 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; // ""

答案 2 :(得分:1)

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

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

现在让我们将它应用于字符串。我在字符串下面添加了字符索引,以便更容易讨论:

a a a a
0123456

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

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

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

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

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

正则表达式@caeth建议(/(^|\s+)a(?=\s|$)/g)之所以有效,是因为?=量词。来自MDN Regexp Documentation

  

仅当x后跟y时才匹配x。例如,/Jack(?=Sprat)/匹配"杰克"只有当它跟随" Sprat"。 /Jack(?=Sprat|Frost)/匹配"杰克"只有当它跟随着#34; Sprat"或者" Frost"。然而," Sprat"也不是"弗罗斯特"是比赛结果的一部分。

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

答案 3 :(得分:1)

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

试试这个。$1。见。演示。

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

答案 4 :(得分:0)

请改用:

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

使用" *这将替换所有" a"出现

问候

答案 5 :(得分:0)

或者您可以将字符串拆分,过滤并将其粘合回来:

"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'