Here is a way:
String.prototype.replaceAll = String.prototype.replaceAll || function(needle, replacement) {
return this.split(needle).join(replacement);
};
Just put it before any other script you use replaceAll
. Use it as follows:
var novaString = 'foo bar foo'.replaceAll('foo', 'baz');
console.log(novaString); //"baz bar baz"
While putting the function in the prototype is very convenient, there are a few reasons not to do so -- if a library, script or new Ecmascript specification defines another String.prototype.replaceAll
with different signature or behavior there would be conflict. We can convert this into a simple function to be more future-proof:
function replaceAll(str, needle, replacement) {
return str.split(needle).join(replacement);
}
console.log( replaceAll('foo bar foo', 'foo', 'baz') ); //"baz bar baz"
What’s wrong with using regex?
None, really. However, I believe it is much easier to work with strings. If you want to create a regex from an arbitrary string, it is necessary to escape all metacharacters. Another method using regex:
String.prototype.replaceAll || (function() {
var regMetaChars = /[-\\^$*+?.()|[\]{}]/g;
String.prototype.replaceAll = function(needle, replacement) {
return this.replace(new RegExp(needle.replace(regMetaChars, '\\$&'), 'g'), replacement);
};
}());
But it is not easier to write a literal regex?
This will depend on your use case. If you don’t know much about Regex, you might encounter syntax errors or unexpected results if you don’t escape the metacharacters properly. For example:
'a.a'.replace(/./g, ','); //Qual o resultado?
A user with no Regex experience would expect "a,a"
, but since the endpoint is a meta-character that represents a character class containing all characters (except line breaks), the result of the above expression is ",,,"
. A correct regex would be /\./g
, which would replace only the character .
.
Even though you have full knowledge of all metacharacters that need to be escaped, another important point is when the text to be replaced (Needle) is a variable whose content may be unknown. So it is necessary to escape all possible metacharacters through one more replace
before passing it on to the builder RegExp
(since it is not possible to place a variable inside the literal syntax of Regexp objects).
It is therefore easier to use a function when its use case requires something more complex.
Wouldn’t it be easier just to loop while the Needle is found?
There is a problem with the OP code. Let’s put it in a function and analyze:
function replaceAll(str, needle, replacement) {
var i = 0;
while ((i = str.indexOf(needle, i)) != -1) {
str = str.replace(needle, replacement);
}
return str;
}
The indexOf
and replace
of each iteration begin scanning the string from its beginning. This generates bugs in certain cases:
replaceAll('bbaa', 'ba', ''); //Qual o resultado?
We would expect the method to find the Needle (highlighted in square brackets) b[ba]a
, replace it with an empty string, find no more Needle the part of the current position and return ba
. However, as the scan resumes from the beginning of the string at each iteration, this function finds ba
a second time and the return is an empty string.
To fix this it is necessary to pass the i
as the second argument of indexOf()
(fromIndex
), and since the replace()
does not have a parameter fromIndex
it would be necessary substring
/substr
/slice
to simulate it, which would make the code a little more complex, but also functional:
String.prototype.replaceAll = String.prototype.replaceAll || function(needle, replacement) {
var str = this,
i = 0,
l = needle.length;
while (~(i = str.indexOf(needle, i))) {
str = str.substr(0, i) + str.substr(i+l);
}
return str;
};
I did tests with the 3 ways and found that this is really the fastest. Using split is very fast too, but with regex is better.
– Daniel T. Sobrosa
@Danielt.Sobrosa Yes, regex is a good tool to have in the belt. = ) Btw, thanks for editing -- I had to apply it manually because the revision interface bugged. I don’t know if it was something local -- if it shows up again, I’ll report it.
– elias
Be careful only if your string contains characters with special meaning in regular expressions (., +, *, [ etc.). In this solution, such characters must be "escaped" with ''. See http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
– rodrigorgs
@rodrigorgs Yes, in these cases it is good to test there in Regexpal, so I’ve put the link. =)
– elias
Okay, thank you very much.
– Daniel T. Sobrosa
It’s not standard but it’s nice to remember that you can pass the third parameter as a regular expression flag in the replace method, for example:
str = str.replace('_', ' ', 'g');
works like the example, but some non-modern browsers may not show the expected behavior (there is Shim to fix this).– Gabriel Gartz