Comment remplacer toutes les occurrences d'une chaîne en JavaScript?


J'ai cette chaîne:

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

Faire

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

semble supprimer seulement la première occurrence de abc dans la chaîne ci-dessus. Comment puis-je remplacer toutes les occurrences de celui-ci?


Answers



Par souci d'exhaustivité, j'ai réfléchi à la méthode que je devrais utiliser pour faire cela. Il y a essentiellement deux façons de le faire comme suggéré par les autres réponses sur cette page.

Remarque: En règle générale, l'extension des prototypes intégrés en JavaScript n'est généralement pas recommandée. Je fournis en tant qu'extensions sur le prototype String à des fins d'illustration, montrant différentes implémentations d'une méthode standard hypothétique sur le prototype intégré String .

Implémentation basée sur l'expression régulière

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

Diviser et joindre (fonctionnel) Implémentation

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

Ne sachant pas trop comment les expressions régulières fonctionnent dans les coulisses en termes d'efficacité, j'ai eu tendance à pencher vers la scission et à rejoindre la mise en œuvre dans le passé sans penser à la performance. Quand je me suis demandé ce qui était le plus efficace, et par quelle marge, je l'ai utilisé comme une excuse pour le savoir.

Sur mon ordinateur Windows 8 Chrome, l'implémentation basée sur l'expression régulière est la plus rapide , l' implémentation de la division et de la jointure étant 53% plus lente . Ce qui signifie que les expressions régulières sont deux fois plus rapides pour l'entrée lorem ipsum que j'ai utilisée.

Découvrez ce cas- test en exécutant ces deux implémentations les unes par rapport aux autres.

Comme indiqué dans le commentaire ci-dessous par @ThomasLeduc et d'autres, il pourrait y avoir un problème avec l'implémentation basée sur l'expression régulière si la search contient certains caractères qui sont réservés en tant que caractères spéciaux dans les expressions régulières . L'implémentation suppose que l'appelant va au préalable échapper à la chaîne ou ne transmettra que les chaînes sans les caractères de la table dans les expressions régulières (MDN).

MDN fournit également une implémentation pour échapper à nos chaînes. Ce serait bien si cela était aussi standardisé avec RegExp.escape(str) , mais hélas, il n'existe pas:

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

Nous pourrions appeler escapeRegExp dans notre implémentation de String.prototype.replaceAll , cependant, je ne suis pas sûr de combien cela affectera les performances (potentiellement même pour les chaînes pour lesquelles l'échappement n'est pas nécessaire, comme toutes les chaînes alphanumériques).




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

En réponse à un commentaire:

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

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

En réponse au commentaire de Click Upvote , vous pouvez le simplifier encore plus:

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

Remarque: Les expressions régulières contiennent des caractères spéciaux (méta) et, en tant que tels, il est dangereux de passer aveuglément un argument dans la fonction de find ci-dessus sans le pré-traiter pour échapper ces caractères. Ceci est couvert dans le Guide JavaScript sur les expressions régulières de Mozilla Developer Network , où ils présentent la fonction d'utilité suivante:

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

Ainsi, afin de rendre la fonction replaceAll() plus sûre, il pourrait être modifié comme suit si vous incluez également escapeRegExp :

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



Note: Ne l'utilisez pas en code réel.

Comme alternative aux expressions régulières pour une chaîne littérale simple, vous pouvez utiliser

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

Le modèle général est

str.split(search).join(replacement)

Cela était plus rapide dans certains cas que d'utiliser replaceAll et une expression régulière, mais cela ne semble plus être le cas dans les navigateurs modernes. Donc, cela ne devrait vraiment être utilisé comme un hack rapide pour éviter d'avoir besoin d'échapper à l'expression régulière, pas en code réel.




L'utilisation d'une expression régulière avec l'ensemble d'indicateurs g remplacera tous:

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

Voir ici aussi




Voici une fonction de prototype de chaîne basée sur la réponse acceptée:

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

MODIFIER

Si votre find contient des caractères spéciaux, vous devez leur échapper:

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

Fiddle: http://jsfiddle.net/cdbzL/




Mettre à jour:

C'est un peu tard pour une mise à jour, mais depuis que je suis tombé sur cette question, j'ai remarqué que ma réponse précédente n'en est pas une. Puisque la question impliquait de remplacer un seul mot, il est incroyable que personne n'ait pensé à utiliser des limites de mots ( \b )

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

C'est une regex simple qui évite de remplacer des parties de mots dans la plupart des cas. Cependant, un tiret - est toujours considéré comme une limite de mot. Ainsi, les conditionnels peuvent être utilisés dans ce cas pour éviter de remplacer les chaînes comme 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"

En gros, cette question est la même que la question ici: Javascript remplace "'" par "' '"

@Mike, cochez la réponse que j'ai donnée ici ... regexp n'est pas le seul moyen de remplacer plusieurs occurrences d'un subsrting, loin de là. Pensez flexible, pensez divisé!

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

Alternativement, pour éviter de remplacer des parties de mot - que la réponse approuvée fera, aussi! Vous pouvez contourner ce problème en utilisant des expressions régulières qui, je le reconnais, sont un peu plus complexes et, par conséquent, un peu plus lentes:

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

La sortie est la même que la réponse acceptée, cependant, en utilisant l'expression / cat / g sur cette chaîne:

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" ?? 

Oups en effet, ce n'est probablement pas ce que vous voulez. Qu'est-ce que c'est, alors? IMHO, une regex qui remplace seulement «chat» conditionnellement. (c'est-à-dire ne fait pas partie d'un mot), comme ceci:

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"

Ma conjecture est, cela répond à vos besoins. Ce n'est pas complètement étanche, bien sûr, mais cela devrait suffire pour vous aider à démarrer. Je vous recommande de lire plus sur ces pages. Cela s'avérera utile pour perfectionner cette expression pour répondre à vos besoins spécifiques.

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

http://www.regular-expressions.info

Dernier ajout:

Étant donné que cette question obtient encore beaucoup de points de vue, j'ai pensé que je pourrais ajouter un exemple de .replace utilisé avec une fonction de rappel. Dans ce cas, il simplifie considérablement l'expression et offre encore plus de flexibilité, comme le remplacement avec une capitalisation correcte ou le remplacement des cat et des cats en une seule fois:

'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



Correspondance avec une expression régulière globale:

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



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

Ou essayez la fonction replaceAll d'ici:

Quelles sont les méthodes JavaScript utiles qui étendent les objets intégrés?

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

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

EDIT: Clarification sur la disponibilité de replaceAll

La méthode 'replaceAll' est ajoutée au prototype de String. Cela signifie qu'il sera disponible pour tous les objets / littéraux de chaîne.

Par exemple

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



Utilisez une expression régulière:

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



C'est la version la plus rapide qui n'utilise pas d'expressions régulières .

Jsperf révisé

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

C'est presque deux fois plus rapide que la méthode split et join.

Comme indiqué dans un commentaire ici, cela ne fonctionnera pas si votre variable omit contient un place , comme dans: replaceAll("string", "s", "ss") , car il sera toujours capable de remplacer une autre occurrence du mot .

Il y a un autre jsperf avec des variantes sur mon remplacement récursif qui vont encore plus vite ( http://jsperf.com/replace-all-vs-split-join/12 )!

  • Mise à jour 27 Juillet 2017: Il semble que RegExp a maintenant la performance la plus rapide dans le Chrome 59 récemment publié.



// boucle en boucle jusqu'à ce que les occurrences de nombre arrivent à 0. OU simplement copier / coller

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



Supposons que vous souhaitiez remplacer tous les 'abc' par '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

J'essayais de penser à quelque chose de plus simple que de modifier le prototype de chaîne.




Simple...

Remplacer des guillemets simples:

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






Si ce que vous voulez trouver se trouve déjà dans une chaîne, et que vous n'avez pas d'escape regex à portée de main, vous pouvez utiliser 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');



J'aime cette méthode (elle a l'air un peu plus propre):

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



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



Si vous essayez de vous assurer que la chaîne que vous recherchez n'existera pas même après le remplacement, vous devez utiliser une boucle.

Par exemple:

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

Lorsque vous avez terminé, vous aurez toujours 'test abc'!

La boucle la plus simple pour résoudre ceci serait:

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

Mais cela fonctionne le remplacement deux fois pour chaque cycle. Peut-être (au risque d'être rejeté) qui peut être combiné pour une forme un peu plus efficace mais moins lisible:

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

Cela peut être particulièrement utile lorsque vous recherchez des chaînes en double.
Par exemple, si nous avons 'a ,,, b' et que nous souhaitons supprimer toutes les virgules en double.
[Dans ce cas, on pourrait faire .replace (/, + / g, ','), mais à un certain point, l'expression rationnelle devient complexe et assez lente pour tourner à la place.]




Vous pouvez simplement utiliser la méthode ci-dessous

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



Bien que les gens aient mentionné l'utilisation de regex, il y a une meilleure approche si vous voulez remplacer le texte quel que soit le cas du texte. Comme les majuscules ou les minuscules. Utilisez la syntaxe suivante

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

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

Vous pouvez consulter l'exemple détaillé ici .




Ajoutez simplement /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 signifie global




La fonction suivante fonctionne pour moi:

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

appelle maintenant les fonctions comme ceci:

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

Il suffit de copier et coller ce code dans la console de votre navigateur pour TEST.




Ma mise en œuvre, très explicite

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



J'utilise p pour stocker le résultat du remplacement de récursion précédent:

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

Il remplacera toutes les occurrences de la chaîne s jusqu'à ce que cela soit possible:

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

Pour éviter une boucle infinie, je vérifie si le remplacement r contient une correspondance m :

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



La plupart des gens font probablement ceci pour encoder une URL. Pour encoder une URL, vous ne devez pas seulement considérer les espaces, mais convertir la chaîne entière correctement avec encodeURI .

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

obtenir:

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



Si la chaîne contient un modèle similaire à abccc, utilisez:

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



Pour remplacer tous les caractères, essayez ce code:

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

Donc, cette méthode va résoudre ce problème.

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 \\"*/

J'utilisais Ajax, et j'avais le besoin d'envoyer des paramètres au format JSON. Alors ma méthode ressemble à ceci:

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



Si l'utilisation d'une bibliothèque est une option pour vous, vous bénéficierez des avantages du test et du support de la communauté associés à une fonction de bibliothèque. Par exemple, la bibliothèque string.js a une fonction replaceAll () qui fait ce que vous cherchez:

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