What is the correct way to do a regular replacement in JavaScript for all occurrences found?

31

What is the correct way to do a regular replacement in JavaScript for all occurrences found?

The way I currently do:

var i = 0;
while ((i = str.indexOf("_", i)) != -1) {
    str = str.replace("_", " ");
}

Or until:

str = str.split("_").join(" ");

They do not seem to be the most appropriate .

    
asked by anonymous 12.12.2013 / 12:20

4 answers

50

Use a regular expression in the first argument of replace with the flag g (global):

str = str.replace(/_/g, ' ');

Read more:

12.12.2013 / 12:22
14

Here's a way:

String.prototype.replaceAll = String.prototype.replaceAll || function(needle, replacement) {
    return this.split(needle).join(replacement);
};

Just put it before any other script that uses replaceAll . Use it as follows:

 var novaString = 'foo bar foo'.replaceAll('foo', 'baz');
 console.log(novaString); //"baz bar baz"
Although putting the function in the prototype is very convenient, there are some reasons not to do so - if a library, script, or new ECMAScript specification sets 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 the problem with using regex?

None, actually. 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 meta-characters. 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 is not it easier to write a literal regex?

This will depend on your use case. If you are not very knowledgeable about Regex, you may encounter syntax errors or unexpected results if the meta-characters do not escape properly. For example:

'a.a'.replace(/./g, ','); //Qual o resultado?

A user with no experience with Regex would expect "a,a" , but since the endpoint is a meta-character representing a character class containing all characters (except line breaks), the result of the above expression is ",,," . The correct regex would be /\./g , which would replace only the . character.

Even though you have full knowledge of all meta-characters that need to be escaped, another important point is when the text to be replaced ( needle ) is a variable whose contents may be unknown. Then it is necessary to escape all possible meta-characters by one more replace before passing it to the RegExp constructor (since it is not possible to put a variable inside the literal syntax of RegExp objects).

So it's easier to use a function when your use case requires something more complex.

Would not it be easier to simply loop while needle is found?

There is a problem with the OP code. Let's put it in a function and analyze it:

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 begins to scan the string from its beginning. This causes bugs in certain cases:

replaceAll('bbaa', 'ba', ''); //Qual o resultado?

We would expect the method to find the needle (highlighted in brackets) b[ba]a , replace it with an empty string, find no more needle the part of the position current and return ba . However, as scanning resumes from the beginning of the string at each iteration, this function finds ba a second time and return is an empty string.

In order to fix this it is necessary to pass i as the second argument of indexOf() ( fromIndex ), and since replace() does not have a parameter fromIndex would require substring / substr / slice to simulate it, which would make the code a bit 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;
};
    
01.02.2014 / 12:46
3

The most correct (and recommended) form is how @elias replied, via regex.

As a matter of curiosity, the Firefox engine (SpiderMonkey) implements an extra parameter in the replace called flags that accepts the same flags normally used with regex .

Example:

>>> "Ah é natal... Feliz Natal!".replace("natal", "ano novo", "gi")  
"Ah é ano novo... Feliz ano novo!"

I do not recommend using this method, it is not standard. It probably will not work in Internet Explorer or Chrome (V8).

    
12.12.2013 / 12:53
0

A simple way would be:

var boia1 = 'Posição+Projeto+-+Boia+8'
    while(boia1.includes('+'))
    {
        boia1 = boia1.replace('+', ' ');
    }

    //Result: 'Posição Projeto - Boia 8'
    
29.11.2016 / 13:52