替换字符串中所有字符实例的最快方法

Anr*_*rgh 619 javascript string replace

在JavaScript中替换字符串中所有字符串/字符实例的最快方法是什么?A while,a for-loop,正则表达式?

Gum*_*mbo 1052

最简单的方法是使用带有gflag 的正则表达式来替换所有实例:

str.replace(/foo/g, "bar")
Run Code Online (Sandbox Code Playgroud)

这将替换所有出现的foobar字符串中str.如果你只有一个字符串,你可以将它转换为RegExp对象,如下所示:

var pattern = "foobar",
    re = new RegExp(pattern, "g");
Run Code Online (Sandbox Code Playgroud)

  • 我内心的学究者指出,OP要求最快,而不是最简单 (81认同)
  • @JaredTomaszewski,正则表达式中的句号(句点)代表"任何角色".要表示一个实际的句号,你需要在它前面加一个反斜杠,即user.email.replace(/\ ./ g,',') (22认同)
  • 警告:这不适用于包含换行符的字符串.XRegExp有一个替换方法可以解决问题. (8认同)
  • 我做了`user.email.replace(/./ g,',')`,整个电子邮件被替换为与电子邮件中的字符数相同的逗号.困惑... (4认同)
  • str.replace(/ foo/g,"bar")给我造成了错误.str.replace(/ foo /,"bar")有效. (2认同)

小智 132

试试这个替换所有:http://dumpsite.com/forum/index.php?topic = 4.msg8 #msg8

String.prototype.replaceAll = function(str1, str2, ignore) 
{
    return this.replace(new RegExp(str1.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g,"\\$&"),(ignore?"gi":"g")),(typeof(str2)=="string")?str2.replace(/\$/g,"$$$$"):str2);
} 
Run Code Online (Sandbox Code Playgroud)

它非常快,它适用于许多其他失败的所有这些条件:

"x".replaceAll("x", "xyz");
// xyz

"x".replaceAll("", "xyz");
// xyzxxyz

"aA".replaceAll("a", "b", true);
// bb

"Hello???".replaceAll("?", "!");
// Hello!!!
Run Code Online (Sandbox Code Playgroud)

让我知道你是否可以打破它,或者你有更好的东西,但要确保它可以通过这4个测试.

  • @jens 我要说的是一个巨大的 CAVEAT EMPTOR。正则表达式非常复杂,一个随机的互联网答案应该一劳永逸地解决某人的问题,但很可能有一些潜在的错误,这确实是一个糟糕的答案。我们不期望对明显正确的答案进行单元测试——当然不是。但我们确实希望,当一个没有经验的程序员很可能被误导成错误的信心时,这些答案能让读者正确理解他们的风险。我的评论有助于警告那些初学者不要相信这种未经测试的疯狂代码。 (2认同)
  • 由于现在有一个标准的 [`replaceAll`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll) 方法,因此这个答案现在会覆盖它。请首先检查属性是否存在来[正确进行猴子修补](/a/46491279/4642212)! (2认同)

San*_*nen 84

var mystring = 'This is a string';
var newString = mystring.replace(/i/g, "a");
Run Code Online (Sandbox Code Playgroud)

newString现在是'Thas as strang'


Vla*_*ada 40

你也可以尝试:

string.split('foo').join('bar');
Run Code Online (Sandbox Code Playgroud)

  • 这是最简单的情况下的完美选择。在一个很好的小函数中运行良好,例如:`function replaceAll(s,f,r){return s.split(f).join(r); }`。或者,如果您认为RegEx更快:`function replaceAll(s,f,r){f = RegExp(f,'gi'); 返回s.replace(f,r); }`。然后只需执行foo = replaceAll('aaa','a','b');`。 (2认同)

ssa*_*l68 12

您可以使用以下内容:

newStr = str.replace(/[^a-z0-9]/gi, '_');
Run Code Online (Sandbox Code Playgroud)

要么

newStr = str.replace(/[^a-zA-Z0-9]/g, '_');
Run Code Online (Sandbox Code Playgroud)

这将取代所有非字母或数字的字符('_').只需更改下划线值即可替换它.

  • 应该是 .replace(/[a-zA-Z0-9]/g, '_') 没有 ^ (3认同)

小智 11

从速度问题考虑它我相信上面链接中提供的区分大小写示例将是迄今为止最快的解决方案.

var token = "\r\n";
var newToken = " ";
var oldStr = "This is a test\r\nof the emergency broadcasting\r\nsystem.";
newStr = oldStr.split(token).join(newToken);
Run Code Online (Sandbox Code Playgroud)

newStr将是"这是对紧急广播系统的测试."


Ric*_*lde 9

我认为真正的答案是它完全取决于你的输入是什么样的.我创建了一个JsFiddle来尝试一堆这些以及我自己的几个输入.无论我如何看待结果,我都看不出明显的赢家.

  • RegExp在任何测试用例中都不是最快的,但它也不错.
  • 对于稀疏替换,拆分/加入方法似乎最快.
  • 对于小输入和密集替换,我写的这个似乎最快:

    function replaceAllOneCharAtATime(inSource, inToReplace, inReplaceWith) {
        var output="";
        var firstReplaceCompareCharacter = inToReplace.charAt(0);
        var sourceLength = inSource.length;
        var replaceLengthMinusOne = inToReplace.length - 1;
        for(var i = 0; i < sourceLength; i++){
            var currentCharacter = inSource.charAt(i);
            var compareIndex = i;
            var replaceIndex = 0;
            var sourceCompareCharacter = currentCharacter;
            var replaceCompareCharacter = firstReplaceCompareCharacter;
            while(true){
                if(sourceCompareCharacter != replaceCompareCharacter){
                output += currentCharacter;
                break;
            }
            if(replaceIndex >= replaceLengthMinusOne) {
                i+=replaceLengthMinusOne;
                output += inReplaceWith;
                //was a match
                break;
            }
            compareIndex++; replaceIndex++;
            if(i >= sourceLength){
                // not a match
                break;
            }
            sourceCompareCharacter = inSource.charAt(compareIndex)
                replaceCompareCharacter = inToReplace.charAt(replaceIndex);
            }   
            replaceCompareCharacter += currentCharacter;
        }
        return output;
    }
    
    Run Code Online (Sandbox Code Playgroud)


小智 8

像这样使用Regex对象

var regex = new RegExp('"', 'g'); str = str.replace(regex, '\'');

它将取代所有发生"'.

  • 在针是变量的情况下,其他答案不起作用,而这个答案效果很好。 (2认同)

Cro*_*zin 5

什么是我不知道的最快,但我知道什么是最可读的 - 什么是最短和最简单的.即使它比其他解决方案稍慢,也值得使用.

所以使用:

 "string".replace("a", "b");
 "string".replace(/abc?/g, "def");
Run Code Online (Sandbox Code Playgroud)

并享受良好的代码而不是更快(好吧...... 1/100000秒并没有区别)和丑陋的代码.;)


Fra*_*tti 5

我意识到我在大约10年前编写的这个实现实际上并没有完全发挥作用(在一个长期被遗忘的系统中讨厌的生产错误,并不总是这样的方式?),我尝试了一些这些建议. ...我注意到的是我尝试的那些(我没有全部尝试过)与我的问题有同样的问题,也就是说,它们不会取代每一次,只有第一次,至少对我的测试案例而言将"test .... txt"改为"test.txt",将".."替换为"."......也许我错过了正则表达式的情况?但我离题了......

所以,我重写了我的实现如下.这很简单,虽然我怀疑不是最快,但我也不认为这种差异会影响现代JS引擎,除非你在紧密的循环中做到这一点,但事情总是如此......

function replaceSubstring(inSource, inToReplace, inReplaceWith) {

  var outString = inSource;
  while (true) {
    var idx = outString.indexOf(inToReplace);
    if (idx == -1) {
      break;
    }
    outString = outString.substring(0, idx) + inReplaceWith +
      outString.substring(idx + inToReplace.length);
  }
  return outString;

}
Run Code Online (Sandbox Code Playgroud)

希望有人帮助!

  • 如果inToReplace是inReplaceWith的子字符串,则无法工作.无限循环. (5认同)

Zib*_*bri 5

我刚刚编写了一个基准测试并测试了前 3 个答案。似乎对于短字符串(<500 个字符)
,第三多投票的答案比第二多投票的答案要快。

对于长字符串(将“.repeat(300)”添加到测试字符串)更快的是答案 1,然后是第二个和第三个。

笔记:

以上适用于使用 v8 引擎(chrome/chromium 等)的浏览器。
使用 firefox(SpiderMonkey 引擎),结果完全不同,
请自行检查!!使用第三个解决方案的 Firefox 似乎
比使用第一个解决方案的 Chrome 快 4.5 倍以上......疯狂:D

function log(data) {
  document.getElementById("log").textContent += data + "\n";
}

benchmark = (() => {

  time_function = function(ms, f, num) {
    var z;
    var t = new Date().getTime();
    for (z = 0;
      ((new Date().getTime() - t) < ms); z++) f(num);
    return (z / ms)
  } // returns how many times the function was run in "ms" milliseconds.


  function benchmark() {
    function compare(a, b) {
      if (a[1] > b[1]) {
        return -1;
      }
      if (a[1] < b[1]) {
        return 1;
      }
      return 0;
    }

    // functions

    function replace1(s) {
      s.replace(/foo/g, "bar")
    }

String.prototype.replaceAll2 = function(_f, _r){ 

  var o = this.toString();
  var r = '';
  var s = o;
  var b = 0;
  var e = -1;
//      if(_c){ _f = _f.toLowerCase(); s = o.toLowerCase(); }

  while((e=s.indexOf(_f)) > -1)
  {
    r += o.substring(b, b+e) + _r;
    s = s.substring(e+_f.length, s.length);
    b += e+_f.length;
  }

  // Add Leftover
  if(s.length>0){ r+=o.substring(o.length-s.length, o.length); }

  // Return New String
  return r;
};

String.prototype.replaceAll = function(str1, str2, ignore) {
      return this.replace(new RegExp(str1.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g, "\\$&"), (ignore ? "gi" : "g")), (typeof(str2) == "string") ? str2.replace(/\$/g, "$$$$") : str2);
    }

    function replace2(s) {
      s.replaceAll("foo", "bar")
    }

    function replace3(s) {
      s.split('foo').join('bar');
    }

    function replace4(s) {
      s.replaceAll2("foo", "bar")
    }


    funcs = [
      [replace1, 0],
      [replace2, 0],
      [replace3, 0],
      [replace4, 0]
    ];

    funcs.forEach((ff) => {
      console.log("Benchmarking: " + ff[0].name);
      ff[1] = time_function(2500, ff[0], "foOfoobarBaR barbarfoobarf00".repeat(10));
      console.log("Score: " + ff[1]);

    })
    return funcs.sort(compare);
  }

  return benchmark;
})()
log("Starting benchmark...\n");
res = benchmark();
console.log("Winner: " + res[0][0].name + " !!!");
count = 1;
res.forEach((r) => {
  log((count++) + ". " + r[0].name + " score: " + Math.floor(10000 * r[1] / res[0][1]) / 100 + ((count == 2) ? "% *winner*" : "% speed of winner.") + " (" + Math.round(r[1] * 100) / 100 + ")");
});
log("\nWinner code:\n");
log(res[0][0].toString());
Run Code Online (Sandbox Code Playgroud)
<textarea rows="50" cols="80" style="font-size: 16; resize:none; border: none;" id="log"></textarea>
Run Code Online (Sandbox Code Playgroud)

当您单击按钮时,测试将运行 10 秒(+2 秒)。

我的结果(在同一台电脑上):

Chrome/Linux Ubuntu 64:
1. replace1 score: 100% *winner* (766.18)
2. replace4 score: 99.07% speed of winner. (759.11)
3. replace3 score: 68.36% speed of winner. (523.83)
4. replace2 score: 59.35% speed of winner. (454.78)

Firefox/Linux Ubuntu 64
1. replace3 score: 100% *winner* (3480.1)
2. replace1 score: 13.06% speed of winner. (454.83)
3. replace4 score: 9.4% speed of winner. (327.42)
4. replace2 score: 4.81% speed of winner. (167.46)
Run Code Online (Sandbox Code Playgroud)

好乱啊?

随意添加更多测试结果

Chrome/Windows 10
1. replace1 score: 100% *winner* (742.49)
2. replace4 score: 85.58% speed of winner. (635.44)
3. replace2 score: 54.42% speed of winner. (404.08)
4. replace3 score: 50.06% speed of winner. (371.73)

Firefox/Windows 10
1. replace3 score: 100% *winner* (2645.18)
2. replace1 score: 30.77% speed of winner. (814.18)
3. replace4 score: 22.3% speed of winner. (589.97)
4. replace2 score: 12.51% speed of winner. (331.13)

Edge/Windows 10
1. replace1 score: 100% *winner* (1251.24)
2. replace2 score: 46.63% speed of winner. (583.47)
3. replace3 score: 44.42% speed of winner. (555.92)
4. replace4 score: 20% speed of winner. (250.28)
Run Code Online (Sandbox Code Playgroud)

Galaxy Note 4 上的 Chrome

1. replace4 score: 100% *winner* (99.82)
2. replace1 score: 91.04% speed of winner. (90.88)
3. replace3 score: 70.27% speed of winner. (70.15)
4. replace2 score: 38.25% speed of winner. (38.18)
Run Code Online (Sandbox Code Playgroud)