如何在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;
}