¿Cómo reemplazar todas las apariciones de una cadena en JavaScript?


Tengo esta cadena:

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

Obra

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

parece solo eliminar la primera aparición de abc en la cadena de arriba. ¿Cómo puedo reemplazar todas las apariciones?


Answers



Para completar, comencé a pensar qué método debería usar para hacer esto. Básicamente, hay dos maneras de hacerlo, tal como lo sugieren las otras respuestas en esta página.

Nota: en general, no se recomienda extender los prototipos incorporados en JavaScript. Proporciono extensiones en el prototipo de cadena simplemente con fines de ilustración, que muestran diferentes implementaciones de un método estándar hipotético en el prototipo integrado String .

Implementación basada en expresiones regulares

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

Dividir y unir (Funcional) Implementación

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

Como no sabía demasiado sobre cómo las expresiones regulares funcionan detrás de escena en términos de eficiencia, tendía a inclinarme hacia la división y unirme a la implementación en el pasado sin pensar en el rendimiento. Cuando me pregunté cuál era más eficiente, y con qué margen, lo usé como una excusa para descubrirlo.

En mi máquina Chrome para Windows 8, la implementación basada en expresiones regulares es la más rápida , con la implementación de split y join un 53% más lenta . Lo que significa que las expresiones regulares son dos veces más rápidas para la entrada lorem ipsum que utilicé.

Vea este benchmark ejecutando estas dos implementaciones entre sí.

Como se señala en el comentario a continuación por @ThomasLeduc y otros, podría haber un problema con la implementación basada en expresiones regulares si la search contiene ciertos caracteres que están reservados como caracteres especiales en expresiones regulares . La implementación asume que la persona que llama escapará de la cadena de antemano o que solo pasará cadenas que están sin los caracteres en la tabla en expresiones regulares (MDN).

MDN también proporciona una implementación para escapar de nuestras cadenas. Sería bueno si esto también se estandarizó como RegExp.escape(str) , pero lamentablemente, no existe:

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

Podríamos llamar a escapeRegExp dentro de nuestra implementación String.prototype.replaceAll , sin embargo, no estoy seguro de cuánto afectará esto al rendimiento (potencialmente incluso para cadenas para las cuales no se necesita el escape, como todas las cadenas alfanuméricas).




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

En respuesta al comentario:

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

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

En respuesta al comentario de Click Upvote , podrías simplificarlo aún más:

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

Nota: Las expresiones regulares contienen caracteres especiales (meta), y como tal, es peligroso pasar un argumento a ciegas en la función de find anterior sin preprocesarlo para escapar de esos caracteres. Esto se trata en la Guía de JavaScript de Mozilla Developer Network en expresiones regulares , donde presentan la siguiente función de utilidad:

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

Por lo tanto, para hacer que la función replaceAll() más segura, podría modificarse a lo siguiente si también incluye escapeRegExp :

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



Nota: No use esto en código real.

Como alternativa a las expresiones regulares para una cadena literal simple, podrías usar

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

El patrón general es

str.split(search).join(replacement)

En algunos casos, esto solía ser más rápido que usar replaceAll y una expresión regular, pero eso ya no parece ser el caso en los navegadores modernos. Por lo tanto, esto solo debería usarse realmente como un truco rápido para evitar la necesidad de escapar de la expresión regular, no en el código real.




El uso de una expresión regular con el conjunto de indicadores g reemplazará a todos:

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

Vea aquí también




Aquí hay una función de prototipo de cadena basada en la respuesta aceptada:

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

EDITAR

Si tu find contiene caracteres especiales, entonces debes escapar de ellos:

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

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




Actualizar:

Es algo tarde para una actualización, pero desde que me encontré con esta pregunta, y noté que mi respuesta anterior no es con la que estoy contento. Dado que la pregunta implicaba reemplazar una sola palabra, es increíble que a nadie se le haya ocurrido utilizar límites de palabras ( \b )

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

Esta es una expresión regular simple que evita reemplazar partes de palabras en la mayoría de los casos. Sin embargo, un guion - todavía se considera un límite de palabras. Entonces, los condicionales se pueden usar en este caso para evitar reemplazar cadenas como 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"

básicamente, esta pregunta es la misma que aquí: Javascript reemplaza "'" por "' '"

@Mike, verifique la respuesta que di allí ... la expresión regular no es la única forma de reemplazar múltiples ocurrencias de una subserie, ni mucho menos. ¡Piensa flexible, piensa dividido!

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

Alternativamente, para evitar reemplazar partes de palabras, ¡lo cual también será la respuesta aprobada! Puede solucionar este problema utilizando expresiones regulares que, reconozco, son algo más complejas y, como resultado, un poco más lentas también:

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

El resultado es el mismo que la respuesta aceptada, sin embargo, usando la expresión / cat / g en esta cadena:

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

Oops de hecho, esto probablemente no es lo que quieres. ¿Que es entonces? En mi humilde opinión, una expresión regular que solo reemplaza 'gato' condicionalmente. (es decir, no forma parte de una palabra), así:

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"

Supongo que esto satisface tus necesidades. No es a prueba de todo, por supuesto, pero debería ser suficiente para comenzar. Recomiendo leer un poco más en estas páginas. Esto será útil para perfeccionar esta expresión y satisfacer sus necesidades específicas.

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

http://www.regular-expressions.info

Además final:

Dado que esta pregunta aún recibe muchas vistas, pensé que podría agregar un ejemplo de .replace utilizado con una función de devolución de llamada. En este caso, simplifica enormemente la expresión y proporciona aún más flexibilidad, como reemplazar con mayúsculas o reemplazar cat y cats de una sola vez:

'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



Coincidencia con una expresión regular global:

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



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

O pruebe la función replaceAll desde aquí:

¿Cuáles son los métodos de JavaScript útiles que amplían los objetos incorporados?

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

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

EDIT: aclaración sobre replaceToda disponibilidad

El método 'replaceAll' se agrega al prototipo de String. Esto significa que estará disponible para todos los objetos / literales de cadenas.

P.ej

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



Use una expresión regular:

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



Esta es la versión más rápida que no usa expresiones regulares .

Jsperf revisado

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

Es casi dos veces más rápido que el método de división y unión.

Como se señala en un comentario aquí, esto no funcionará si su variable omit contiene place , como en: replaceAll("string", "s", "ss") , porque siempre será capaz de reemplazar otra ocurrencia de la palabra .

Hay otra jsperf con variantes en mi reemplazo recursivo que van incluso más rápido ( http://jsperf.com/replace-all-vs-split-join/12 ).

  • Actualización 27 de julio de 2017: Parece que RegExp ahora tiene el rendimiento más rápido en el Chrome 59 recientemente lanzado.



// lo bucleo hasta que el número de ocurrencias llegue a 0. O simplemente copie / pegue

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



Digamos que quiere reemplazar todo el 'abc' por '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

Estaba tratando de pensar en algo más simple que modificar el prototipo de cuerda.




Sencillo...

Reemplazar comillas 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 lo que quieres encontrar ya está en una cadena, y no tienes a mano un escarabajo de expresiones regulares, puedes usar 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');



Me gusta este método (se ve un poco más limpio):

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



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



Si intenta asegurarse de que la cadena que está buscando no existirá incluso después del reemplazo, debe usar un ciclo.

Por ejemplo:

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

Cuando se complete, ¡todavía tendrá 'prueba abc'!

El bucle más simple para resolver esto sería:

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

Pero eso ejecuta el reemplazo dos veces para cada ciclo. Quizás (en riesgo de ser rechazado) que se puede combinar para una forma un poco más eficiente pero menos legible:

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

Esto puede ser particularmente útil al buscar cadenas duplicadas.
Por ejemplo, si tenemos 'a ,,, b' y deseamos eliminar todas las comas duplicadas.
[En ese caso, uno podría hacer .replace (/, + / g, ','), pero en algún momento la expresión regular se vuelve compleja y lo suficientemente lenta como para hacer bucles en su lugar.]




Simplemente puede usar el método a continuación

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



Aunque las personas han mencionado el uso de expresiones regulares, pero hay un mejor enfoque si desea reemplazar el texto, independientemente del caso del texto. Como mayúsculas o minúsculas. Use la sintaxis a continuación

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

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

Puede consultar el ejemplo detallado aquí .




Solo agregue /g

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

a

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

/g significa global




La siguiente función funciona para mí:

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

ahora llame a las funciones de esta manera:

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

Simplemente copie y pegue este código en la consola de su navegador para PRUEBA.




Mi implementación, muy explicativa

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



Utilizo p para almacenar el resultado de la sustitución de recursión anterior:

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

Reemplazará todas las ocurrencias en la cadena s hasta que sea posible:

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

Para evitar un ciclo infinito, compruebo si el reemplazo r contiene una coincidencia m :

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



La mayoría de las personas probablemente hagan esto para codificar una URL. Para codificar una URL, no solo debe considerar los espacios, sino también convertir la cadena completa correctamente con encodeURI .

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

Llegar:

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



Si la cadena contiene un patrón similar al uso de abccc use:

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



Para reemplazar todo tipo de caracteres, pruebe este código:

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

Entonces este método resolverá este problema.

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

Estaba usando Ajax, y tuve la necesidad de enviar parámetros en formato JSON. Entonces mi método se ve así:

 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 usar una biblioteca es una opción para usted, obtendrá los beneficios de las pruebas y el apoyo de la comunidad que acompaña a una función de biblioteca. Por ejemplo, la biblioteca string.js tiene una función replaceAll () que hace lo que estás buscando:

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