如何在JavaScript中替换所有出现的字符串?


我有这个字符串:

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

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

似乎只能删除上面字符串中第一次出现的abc 。 我怎样才能取代所有的事件呢?


Answers



为了完整起见,我开始考虑使用哪种方法来做到这一点。 基本上有两种方法可以按照本页其他答案的建议进行操作。

注意:通常,不推荐使用JavaScript扩展内置的原型。 为了说明的目的,我在String原型上作为扩展提供,在String内置原型上显示了假设标准方法的不同实现。

正则表达式的实现

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

拆分和加入(功能)实现

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

我不太了解正则表达式在效率方面如何在幕后工作,我往往倾向于分裂,在过去没有考虑性能的情况下参与实施。 当我想知道哪个更有效率,以什么边际,我用它作为找借口。

在我的Chrome Windows 8机器上, 基于正则表达式的实现速度最快分离和连接实现速度降低了53% 。 这意味着正则表达式是我使用的lorem ipsum输入的两倍。

看看这个基准运行这两个实现对彼此。

正如@ThomasLeduc和其他人在下面的评论中指出的那样,如果search包含某些在正则表达式中保留为特殊字符的字符,那么基于正则表达式的实现可能会出现问题。 该实现假定调用者将事先转义字符串,或者只传递在正则表达式 (MDN)中的表中没有字符的字符串。

MDN也提供了一个实现来逃避我们的字符串。 这将是很好,如果这也是RegExp.escape(str) ,但唉,它不存在:

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

我们可以在我们的String.prototype.replaceAll实现中调用escapeRegExp ,但是我不确定这会影响性能(甚至对于不需要转义的字符串,就像所有的字母数字字符串一样)。




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

回应评论:

var find = 'abc';
var re = new RegExp(find, 'g');

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

为了回应Click Upvote的评论,你可以更简化它:

function replaceAll(str, find, replace) {
    return str.replace(new RegExp(find, 'g'), replace);
}

注意:正则表达式包含特殊(meta)字符,因此在上面的find函数中盲目地传递一个参数而不预先处理它来转义这些字符是危险的。 这在Mozilla开发者网络正则表达式JavaScript指南中有介绍 ,它们提供了以下的实用功能:

function escapeRegExp(str) {
    return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}

因此,为了使上面的replaceAll()函数更安全,如果还包含escapeRegExp ,可以将其修改为以下escapeRegExp

function replaceAll(str, find, replace) {
    return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
}



注意:不要在真实的代码中使用它。

作为一个简单的文字字符串的正则表达式的替代,你可以使用

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

一般模式是

str.split(search).join(replacement)

在使用replaceAll和正则表达式的情况下,这种方法的速度会更快,但在现代浏览器中似乎不再是这种情况。 所以,这实际上只能作为一个快速入侵,以避免需要逃避正则表达式,而不是真正的代码。




使用g标志设置的正则表达式将取代所有:

someString = 'the cat looks like a cat';
anotherString = someString.replace(/cat/g, 'dog');
// anotherString now contains "the dog looks like a dog"

也看到这里




这是一个基于公认的答案的字符串原型函数:

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

编辑

如果你的find将包含特殊字符,那么你需要逃避它们:

String.prototype.replaceAll = function (find, replace) {
    var str = this;
    return str.replace(new RegExp(find.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'), replace);
};

小提琴: http : //jsfiddle.net/cdbzL/




更新:

更新有些晚了,但是因为我偶然发现了这个问题,并且注意到我之前的回答并不是我所满意的。 由于这个问题涉及替换一个单词,这是令人难以置信的,没有人想到使用单词边界( \b

'a cat is not a caterpillar'.replace(/\bcat\b/gi,'dog');
//"a dog is not a caterpillar"

这是一个简单的正则表达式,避免在大多数情况下替换单词的部分。 然而,短划线-仍然被认为是一个字的边界。 所以在这种情况下可以使用条件来避免替换像cool-cat这样的字符串:

'a cat is not a cool-cat'.replace(/\bcat\b/gi,'dog');//wrong
//"a dog is not a cool-dog" -- nips
'a cat is not a cool-cat'.replace(/(?:\b([^-]))cat(?:\b([^-]))/gi,'$1dog$2');
//"a dog is not a cool-cat"

基本上,这个问题和这里的问题是一样的: Javascript用“”替换“”“

@迈克,检查我给了那里的答案...正则表达式是不是唯一的方法来取代多次出现,子离子,远离它。 灵活思考,思考分裂!

var newText = "the cat looks like a cat".split('cat').join('dog');

或者,为了防止替换字的部分,也就是批准的答案。 你可以用正则表达式来解决这个问题,我承认,这个表达式有点复杂,作为一个结果,稍微慢一些:

var regText = "the cat looks like a cat".replace(/(?:(^|[^a-z]))(([^a-z]*)(?=cat)cat)(?![a-z])/gi,"$1dog");

输出与接受的答案相同,但是,在此字符串上使用/ cat / g表达式:

var oops = 'the cat looks like a cat, not a caterpillar or coolcat'.replace(/cat/g,'dog');
//returns "the dog looks like a dog, not a dogerpillar or cooldog" ?? 

糟糕,这可能不是你想要的。 那么是什么? 恕我直言,只是有条件地取代'猫'的正则表达式。 (即不是一个单词的一部分),如下所示:

var caterpillar = 'the cat looks like a cat, not a caterpillar or coolcat'.replace(/(?:(^|[^a-z]))(([^a-z]*)(?=cat)cat)(?![a-z])/gi,"$1dog");
//return "the dog looks like a dog, not a caterpillar or coolcat"

我的猜测是,这符合你的需求。 当然,这不是全面的,但它应该足以让你开始。 我建议阅读更多的这些网页。 这将有助于完善这个表达式来满足您的特定需求。

http://www.javascriptkit.com/jsref/regexp.shtml

http://www.regular-expressions.info

最后加入:

鉴于这个问题仍然有很多观点,我想我可能会添加一个.replace用于回调函数的例子。 在这种情况下,它极大地简化了表达式, 提供了更大的灵活性,例如用正确的大小写替换或一次性替换catcats

'Two cats are not 1 Cat! They\'re just cool-cats, you caterpillar'
   .replace(/(^|.\b)(cat)(s?\b.|$)/gi,function(all,char1,cat,char2)
    {
       //check 1st, capitalize if required
       var replacement = (cat.charAt(0) === 'C' ? 'D' : 'd') + 'og';
       if (char1 === ' ' && char2 === 's')
       {//replace plurals, too
           cat = replacement + 's';
       }
       else
       {//do not replace if dashes are matched
           cat = char1 === '-' || char2 === '-' ? cat : replacement;
       }
       return char1 + cat + char2;//return replacement string
    });
//returns:
//Two dogs are not 1 Dog! They're just cool-cats, you caterpillar



与全球正则表达式匹配:

anotherString = someString.replace(/cat/g, 'dog');



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

或者从这里尝试replaceAll函数:

什么是扩展内置对象的有用的JavaScript方法?

str = str.replaceAll('abc', ''); OR

var search = 'abc';
str = str.replaceAll(search, '');

编辑:澄清关于replaceAll可用性

'replaceAll'方法被添加到String的原型。 这意味着它将可用于所有字符串对象/文字。

例如

var output = "test this".replaceAll('this', 'that');  //output is 'test that'.
output = output.replaceAll('that', 'this'); //output is 'test this'



使用正则表达式:

str.replace(/abc/g, '');



这是不使用正则表达式最快版本。

修正了jsperf

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

它几乎是分割和连接方法的两倍

正如在这里的评论中指出的那样,如果你的omit变量包含place ,那么这将不起作用,如: replaceAll("string", "s", "ss") ,因为它总是能够替换另一个字。

还有另一个与我的递归替换jsperf变得更快( http://jsperf.com/replace-all-vs-split-join/12 )!

  • 2017年7月27日更新:看起来RegExp现在在最近发布的Chrome 59中表现最快。



//循环,直到数字出现为0或者只是复制/粘贴

    function replaceAll(find, replace, str) 
    {
      while( str.indexOf(find) > -1)
      {
        str = str.replace(find, replace);
      }
      return str;
    }



假设你想用'x'代替所有'abc':

let some_str = 'abc def def lom abc abc def'.split('abc').join('x')
console.log(some_str) //x def def lom x x def

我试图想想比修改字符串原型更简单的事情。




简单...

替换单引号:

function JavaScriptEncode(text){
    text = text.replace(/'/g,''')
    // More encode here if required

    return text;
}



function replaceAll(str, find, 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) + replaceAll(st2, find, replace);
    }       
  }
  return str;
}






如果你想找到的东西已经在一个字符串中,而且你没有一个正则表达式,你可以使用join / split:

function replaceMulti(haystack, needle, replacement)
{
    return haystack.split(needle).join(replacement);
}

someString = 'the cat looks like a cat';
anotherString = replaceMulti(someString, 'cat', 'dog');



我喜欢这个方法(看上去有点干净):

text = text.replace(new RegExp("cat","g"), "dog"); 



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



如果您正在尝试确保即使在更换后您所查找的字符串也不存在,则需要使用循环。

例如:

var str = 'test aabcbc';
str = str.replace(/abc/g, '');

完成后,您仍然可以“测试abc”!

解决这个问题的最简单的循环是:

var str = 'test aabcbc';
while (str != str.replace(/abc/g, '')){
   str.replace(/abc/g, '');
}

但是,每个周期运行两次更换。 也许(可能被拒绝)可以组合成一个稍微有效但不太可读的形式:

var str = 'test aabcbc';
while (str != (str = str.replace(/abc/g, ''))){}
// alert(str); alerts 'test '!

这在查找重复的字符串时特别有用。
例如,如果我们有'a ,,, b',我们希望删除所有重复的逗号。
[在这种情况下,可以使用.replace(/,+ / g,','),但是在某些时候,正则表达式变得复杂而且慢得足以循环。]




你可以简单地使用下面的方法

/**
 * Replace all the occerencess of $find by $replace in $originalString
 * @param  {originalString} input - Raw string.
 * @param  {find} input - Target key word or regex that need to be replaced.
 * @param  {replace} input - Replacement key word
 * @return {String}       Output string
 */
function replaceAll(originalString, find, replace) {
  return originalString.replace(new RegExp(find, 'g'), replace);
};



虽然人们已经提到了正则表达式的使用,但是如果要替换文本而不考虑文本的情况,还有更好的方法。 像大写或小写。 使用下面的语法

//Consider below example
originalString.replace(/stringToBeReplaced/gi, '');

//Output will be all the occurrences removed irrespective of casing.

你可以参考这里的详细例子。




只需添加/g

document.body.innerHTML = document.body.innerHTML.replace('hello', 'hi');

// Replace 'hello' string with /hello/g regular expression.
document.body.innerHTML = document.body.innerHTML.replace(/hello/g, 'hi');

/g意味着全球




以下功能适用于我:

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

现在调用这样的函数:

"you could be a Project Manager someday, if you work like this.".replaceAllOccurence ("you", "I");

只需将此代码复制并粘贴到浏览器控制台中即可。




我的实现,非常自我解释

function replaceAll(string, token, newtoken) {
    if(token!=newtoken)
    while(string.indexOf(token) > -1) {
        string = string.replace(token, newtoken);
    }
    return string;
}



我使用p来存储以前的递归替换的结果:

function replaceAll(s, m, r, p) {
    return s === p || r.contains(m) ? s : replaceAll(s.replace(m, r), m, r, s);
}

它将替换字符串s中的所有事件,直到可能:

replaceAll('abbbbb', 'ab', 'a')  'abbbb'  'abbb'  'abb'  'ab'  'a'

为了避免无限循环,我检查替换r是否包含匹配m

replaceAll('abbbbb', 'a', 'ab')  'abbbbb'



大多数人可能会这样做的URL编码。 要对URL进行编码,您不仅应该考虑空格,还应该使用encodeURI正确地转换整个字符串。

encodeURI("http://www.google.com/a file with spaces.html")

要得到:

http://www.google.com/a%20file%20with%20spaces.html



如果字符串包含像abccc类似的模式使用使用:

str.replace(/abc(\s|$)/g,"")



为了替换所有类型的字符,请尝试下面的代码:

Suppose we have need to send " and \ in my string, then we will convert it " to \" and \ to \\

所以这个方法将解决这个问题。

String.prototype.replaceAll = function (find, replace) {
     var str = this;
     return str.replace(new RegExp(find.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'), replace);
 };

var message = $('#message').val();
             message = message.replaceAll('\\', '\\\\'); /*it will replace \ to \\ */
             message = message.replaceAll('"', '\\"');   /*it will replace " to \\"*/

我使用的是Ajax,而且我需要以JSON格式发送参数。 那么我的方法是这样的:

 function sendMessage(source, messageID, toProfileID, userProfileID) {

     if (validateTextBox()) {
         var message = $('#message').val();
         message = message.replaceAll('\\', '\\\\');
         message = message.replaceAll('"', '\\"');
         $.ajax({
             type: "POST",
             async: "false",
             contentType: "application/json; charset=utf-8",
             url: "services/WebService1.asmx/SendMessage",
             data: '{"source":"' + source + '","messageID":"' + messageID + '","toProfileID":"' + toProfileID + '","userProfileID":"' + userProfileID + '","message":"' + message + '"}',
             dataType: "json",
             success: function (data) {
                 loadMessageAfterSend(toProfileID, userProfileID);
                 $("#<%=PanelMessageDelete.ClientID%>").hide();
                 $("#message").val("");
                 $("#delMessageContainer").show();
                 $("#msgPanel").show();
             },
             error: function (result) {
                 alert("message sending failed");
             }
         });
     }
     else {
         alert("Please type message in message box.");
         $("#message").focus();

     }
 }

 String.prototype.replaceAll = function (find, replace) {
     var str = this;
     return str.replace(new RegExp(find.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'), replace);
 };



如果使用库是您的一个选择,那么您将获得与库函数一起使用的测试和社区支持的好处。 例如, string.js库有一个replaceAll()函数,它可以完成你正在寻找的任务:

// Include a reference to the string.js library and call it (for example) S.
str = S(str).replaceAll('abc', '').s;



function replaceAll(str, find, replace) {
    var $r="";
    while($r!=str){ 
        $r = str;
        str = str.replace(find, replace);
    }
    return str;
}