提问



我有这个字符串:


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





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


似乎只删除了上面字符串中第一次出现的abc。如何替换所有次出现?

最佳参考


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


注意:通常,建议不要在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输入的两倍。


查看运行这两个实现的基准[88]





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


MDN还提供了一种逃避字符串的实现。如果这也被标准化为RegExp.escape(str)会很好,但唉,它不存在:


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


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

其它参考1


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);
}


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


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


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


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

其它参考2


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


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


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


一般模式是


str.split(search).join(replacement)


在某些情况下,这比使用replaceAll和正则表达式更快,但在现代浏览器中似乎不再是这种情况。所以,这应该只是用作快速入侵以避免需要逃避正则表达式,而不是真正的代码。

其它参考3


使用带g标志的正则表达式将替换所有:


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


另见


其它参考4


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


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/[95]

其它参考5


更新


对于更新来说有点迟,但是因为我偶然发现了这个问题,并注意到我以前的答案不是我满意的答案。由于问题涉及替换单个单词,所以没有人想到使用单词边界(\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将'替换为''


@Mike,检查我给出的答案... regexp不是替换多次出现的替代品的唯一方法,远非它。想想灵活,想想分裂!


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[97]


http://www.regular-expressions.info [98]





最终补充:


鉴于这个问题仍然有很多观点,我想我可能会添加一个与回调函数一起使用的.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

其它参考6


匹配全局正则表达式:


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

其它参考7


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'

其它参考8


假设您要将所有abc替换为x:


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


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

其它参考9


使用正则表达式:


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

其它参考10


替换单引号:


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

    return text;
}

其它参考11


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


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

其它参考12


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


修订jsperf [100]


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


它几乎两次与split和join方法一样快。


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


在我的递归替换上还有另一个带有变体的jsperf甚至更快(http://jsperf.com/replace-all-vs-split-join/12)![101]



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


其它参考13


str = str.replace(new RegExp("abc", 'g'), "");


比上面的答案更适合我。所以new RegExp("abc", 'g')创建一个RegExp,匹配文本的所有出现('g'标志)("abc")。第二部分是替换为,在你的情况下空字符串("")。
str是字符串,我们必须覆盖它,因为replace(...)只返回结果,但不是覆盖。在某些情况下,您可能想要使用它。

其它参考14


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;
}

其它参考15


var str = "ff ff f f a de def";
str = str.replace(/f/g,'');
alert(str);


http://jsfiddle.net/ANHR9/[102]

其它参考16


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

其它参考17


如果您想要查找的内容已经在字符串中,并且您没有方便的正则表达式,则可以使用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');

其它参考18


我喜欢这种方法(它看起来更干净):


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

其它参考19


如果字符串包含类似abccc的类似模式,则可以使用:


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

其它参考20


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


例如:


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,,),但在某些时候,正则表达式变得复杂而且足够缓慢而不是循环。

其它参考21


您可以简单地使用以下方法


/**
 * 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);
};

其它参考22


var string  = 'Test abc Test abc Test abc Test abc'
string = string.replace(/abc/g, '')
console.log(string)

其它参考23


你可以尝试结合这两种强大的方法。


"test abc test test abc".split("abc").join("")


希望能帮助到你!

其它参考24


只需添加/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意味着全球化

其它参考25


以下功能对我有用:


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");


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

其它参考26


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


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

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


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

其它参考27


JavaScript 中使用RegExp可以为您完成工作,只需执行以下操作即可:


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


如果您考虑重用,请创建一个函数来为您完成,但不推荐它,因为它只是一个行函数,但如果你大量使用它,你可以写这样的东西:


String.prototype.replaceAll = String.prototype.replaceAll || function(string, replaced) {
  return this.replace(new RegExp(string, 'g'), replaced);
};


并简单地在代码中反复使用它,如下所示:


var str ="Test abc test test abc test test test abc test test abc";
str = str.replaceAll('abc', '');


但正如我前面提到的那样,它不会在要编写的行或性能方面产生巨大的差异,只有缓存函数可能会对长字符串产生更快的性能,如果你想重用,也是干代码的良好实践。

其它参考28


我使用 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'

其它参考29


我的实施,非常自我解释


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