How to replace all occurrences of a string?

2020-01-22 11:01发布

I have this string:

"Test abc test test abc test test test abc test test abc"

Doing:

str = str.replace('abc', '');

seems to only remove the first occurrence of abc in the string above.

How can I replace all occurrences of it?

30条回答
Viruses.
2楼-- · 2020-01-22 11:21
while (str.indexOf('abc') !== -1)
{
    str = str.replace('abc', '');
}
查看更多
Deceive 欺骗
3楼-- · 2020-01-22 11:21

The previous answers are way too complicated. Just use the replace function like this:

str.replace(/your_regex_pattern/g, replacement_string);

Example:

var str = "Test abc test test abc test test test abc test test abc";

var res = str.replace(/[abc]+/g, "");

console.log(res);

查看更多
Lonely孤独者°
4楼-- · 2020-01-22 11:22

For the sake of completeness, I got to thinking about which method I should use to do this. There are basically two ways to do this as suggested by the other answers on this page.

Note: In general, extending the built-in prototypes in JavaScript is generally not recommended. I am providing as extensions on the String prototype simply for purposes of illustration, showing different implementations of a hypothetical standard method on the String built-in prototype.


Regular Expression Based Implementation

String.prototype.replaceAll = function(search, replacement) {
    var target = this;
    return target.replace(new RegExp(search, 'g'), replacement);
};

Split and Join (Functional) Implementation

String.prototype.replaceAll = function(search, replacement) {
    var target = this;
    return target.split(search).join(replacement);
};

Not knowing too much about how regular expressions work behind the scenes in terms of efficiency, I tended to lean toward the split and join implementation in the past without thinking about performance. When I did wonder which was more efficient, and by what margin, I used it as an excuse to find out.

On my Chrome Windows 8 machine, the regular expression based implementation is the fastest, with the split and join implementation being 53% slower. Meaning the regular expressions are twice as fast for the lorem ipsum input I used.

Check out this benchmark running these two implementations against each other.


As noted in the comment below by @ThomasLeduc and others, there could be an issue with the regular expression-based implementation if search contains certain characters which are reserved as special characters in regular expressions. The implementation assumes that the caller will escape the string beforehand or will only pass strings that are without the characters in the table in Regular Expressions (MDN).

MDN also provides an implementation to escape our strings. It would be nice if this was also standardized as RegExp.escape(str), but alas, it does not exist:

function escapeRegExp(str) {
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
}

We could call escapeRegExp within our String.prototype.replaceAll implementation, however, I'm not sure how much this will affect the performance (potentially even for strings for which the escape is not needed, like all alphanumeric strings).

查看更多
Melony?
5楼-- · 2020-01-22 11:22

This is the fastest version that doesn't use regular expressions.

Revised jsperf

replaceAll = function(string, omit, place, prevstring) {
  if (prevstring && string === prevstring)
    return string;
  prevstring = string.replace(omit, place);
  return replaceAll(prevstring, omit, place, string)
}

It is almost twice as fast as the split and join method.

As pointed out in a comment here, this will not work if your omit variable contains place, as in: replaceAll("string", "s", "ss"), because it will always be able to replace another occurrence of the word.

There is another jsperf with variants on my recursive replace that go even faster (http://jsperf.com/replace-all-vs-split-join/12)!

  • Update July 27th 2017: It looks like RegExp now has the fastest performance in the recently released Chrome 59.
查看更多
兄弟一词,经得起流年.
6楼-- · 2020-01-22 11:22

Performance

Today 27.12.2019 I perform tests on MacOs HighSierra 10.13.6 for chosen solutions

Conclusions

  • The str.replace(/abc/g, ''); (C) is good-cross-browser fast solution for all strings.
  • Solutions based on split-join (A,B) or replace (C,D) are fast
  • Solutions based on while (E,F,G,H) are slow - usually ~4x slower for small strings and about ~3000x (!) slower for long strings
  • The recurrence solutions (RA,RB) are slow and not works for long strings

I also create my own solution it looks like currently it is the shortest one which do question job

str.split`abc`.join``

str = "Test abc test test abc test test test abc test test abc";
str = str.split`abc`.join``

console.log(str);

Details

The tests was perform on Chrome 79.0, Safari 13.0.4 and Firefox 71.0 (64bit). The tests RA and RB use recurrence. Results

enter image description here

Short string - 55 characters

You can run tests on your machine HERE. Results for chrome

enter image description here

Long string: 275 000 characters

The recursive solutions RA and RB gives

RangeError: Maximum call stack size exceeded

For 1M characters they even break chrome

enter image description here

I try to perform tests for 1M characters for other solutions, but E,F,G,H takes so much time that browser ask me to break script so I shrink test string to 275K characters. You can run tests on your machine HERE. Results for chrome

enter image description here

Code used in tests

var t="Test abc test test abc test test test abc test test abc"; // .repeat(5000)  
var log = (version,result) => console.log(`${version}: ${result}`);


function A(str) { 
  return str.split('abc').join(''); 
}

function B(str) { 
  return str.split`abc`.join``; // my proposition
}


function C(str) { 
  return str.replace(/abc/g, '');          
}

function D(str) { 
  return str.replace(new RegExp("abc", "g"), ''); 
}

function E(str) { 
  while (str.indexOf('abc') !== -1) { str = str.replace('abc', ''); }
  return str;
}

function F(str) { 
  while (str.indexOf('abc') !== -1) { str = str.replace(/abc/, ''); }
  return str;
}

function G(str) { 
  while(str.includes("abc")) { str = str.replace('abc', ''); }
  return str;
}

// src: https://stackoverflow.com/a/56989553/860099
function H(str)
{
    let i = -1
    let find = 'abc';
    let newToken = '';

    if (!str)
    {
        if ((str == null) && (find == null)) return newToken;
        return str;
    }

    while ((
        i = str.indexOf(
            find, i >= 0 ? i + newToken.length : 0
        )) !== -1
    )
    {
        str = str.substring(0, i) +
            newToken +
            str.substring(i + find.length);
    } 
    return str;
}

// src: https://stackoverflow.com/a/22870785/860099
function RA(string, prevstring) {
  var omit = 'abc';
  var place = '';
  if (prevstring && string === prevstring)
    return string;
  prevstring = string.replace(omit, place);
  return RA(prevstring, string)
}

// src: https://stackoverflow.com/a/26107132/860099
function RB(str) {
  var find = 'abc';
  var replace = '';
  var i = str.indexOf(find);
  if (i > -1){
    str = str.replace(find, replace); 
    i = i + replace.length;
    var st2 = str.substring(i);
    if(st2.indexOf(find) > -1){
      str = str.substring(0,i) + RB(st2, find, replace);
    }       
  }
  return str;
}




log('A ', A(t));
log('B ', B(t));
log('C ', C(t));
log('D ', D(t));
log('E ', E(t));
log('F ', F(t));
log('G ', G(t));
log('H ', H(t));
log('RA', RA(t)); // use reccurence 
log('RB', RB(t)); // use reccurence
<p style="color:red">This snippet only presents codes used in tests. It not perform test itself!<p>

查看更多
可以哭但决不认输i
7楼-- · 2020-01-22 11:23

Note: Don't use this in performance critical code.

As an alternative to regular expressions for a simple literal string, you could use

str = "Test abc test test abc test...".split("abc").join("");

The general pattern is

str.split(search).join(replacement)

This used to be faster in some cases than using replaceAll and a regular expression, but that doesn't seem to be the case anymore in modern browsers.

Benchmark: https://jsperf.com/replace-all-vs-split-join

Conclusion: If you have a performance critical use case (e.g processing hundreds of strings), use the Regexp method. But for most typical use cases, this is well worth not having to worry about special characters.

查看更多
登录 后发表回答