How to know if JavaScript string.replace() did any

2019-03-17 04:45发布

问题:

The replace function returns the new string with the replaces, but if there weren't any words to replace, then the original string is returned. Is there a way to know whether it actually replaced anything apart from comparing the result with the original string?

回答1:

A simple option is to check for matches before you replace:

var regex = /i/g;
var newStr = str;

var replaced = str.search(regex) >= 0;
if(replaced){
    newStr = newStr.replace(regex, '!');
}

If you don't want that either, you can abuse the replace callback to achieve that in a single pass:

var replaced = false;
var newStr = str.replace(/i/g, function(token){replaced = true; return '!';});


回答2:

Comparing the before and after strings is the easiest way to check if it did anything, there's no intrinsic support in String.replace().

[contrived example of how '==' might fail deleted because it was wrong]



回答3:

As a workaround you can implement your own callback function that will set a flag and do the replacement. The replacement argument of replace can accept functions.



回答4:

If your replace has a different length from the searched text, you can check the length of the string before and after. I know, this is a partial response, valid only on a subset of the problem.

OR

You can do a search. If the search is successfull you do a replace on the substring starting with the found index and then recompose the string. This could be slower because you are generating 3 strings instead of 2.

var test = "Hellllo";
var index = test.search(/ll/);

if (index >= 0) {
    test = test.substr(0, index - 1) + test.substr(index).replace(/ll/g, "tt");
}

alert(test);


回答5:

Javascript replace is defected by design. Why? It has no compatibility with string replacement in callback.

For example:

"ab".replace(/(a)(b)/, "$1$2")
> "ab"

We want to verify that replace is done in single pass. I was imagine something like:

"ab".replace(/(a)(b)/, "$1$2", function replacing() { console.log('ok'); })
> "ab"

Real variant:

"ab".replace(/(a)(b)/, function replacing() {
  console.log('ok');
  return "$1$2";
})

> ok
> "$1$2"

But function replacing is designed to receive $0, $1, $2, offset, string and we have to fight with replacement "$1$2". The solution is:

"ab".replace(/(a)(b)/, function replacing() {
  console.log('ok');
  // arguments are $0, $1, ..., offset, string
  return Array.from(arguments).slice(1, -2)
  .reduce(function (pattern, match, index) {
    // '$1' from strings like '$11 $12' shouldn't be replaced.
    return pattern.replace(
      new RegExp("\\$" + (index + 1) + "(?=[^\\d]|$)", "g"),
      match
    );
  }, "$1$2");
});

> ok
> "ab"

This solution is not perfect. String replacement itself has its own WATs. For example:

"a".replace(/(a)/, "$01")
> "a"

"a".replace(/(a)/, "$001")
> "$001"

If you want to care about compatibility you have to read spec and implement all its craziness.



回答6:

With indexOf you can check wether a string contains another string.
Seems like you might want to use that.



回答7:

have a look at string.match() or string.search()