¿Cómo reemplazo todas las apariciones de una cadena en JavaScript?
Dada una cadena:
s = "Test abc test test abc test test test abc test test abc";
Esto parece eliminar sólo la primera aparición de abc
en la cadena anterior:
s = s.replace('abc', '');
¿ Cómo reemplazo todas sus apariciones?
A partir de agosto de 2020: los navegadores modernos son compatibles con el String.replaceAll()
método definido por la especificación del lenguaje ECMAScript 2021.
Para navegadores antiguos/heredados:
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
function replaceAll(str, find, replace) {
return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
}
Así es como evolucionó esta respuesta:
str = str.replace(/abc/g, '');
En respuesta al comentario "¿Qué pasa si 'abc' se pasa como variable?":
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 tales, es peligroso pasar ciegamente un argumento en la find
función anterior sin procesarlo previamente para escapar de esos caracteres. Esto se trata en la Guía JavaScript de Mozilla Developer Network sobre expresiones regulares , donde presentan la siguiente función de utilidad (que ha cambiado al menos dos veces desde que se escribió originalmente esta respuesta, así que asegúrese de consultar el sitio de MDN para detectar posibles actualizaciones):
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
Entonces, para que la replaceAll()
función anterior sea 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);
}
Para completar, me puse a pensar qué método debería usar para hacer esto. Básicamente, hay dos formas de hacer esto, como lo sugieren las otras respuestas en esta página.
Nota: En general, no se recomienda ampliar los prototipos integrados en JavaScript. Proporciono extensiones del prototipo String simplemente con fines ilustrativos, mostrando diferentes implementaciones de un método estándar hipotético en el String
prototipo incorporado.
Implementación basada en expresiones regulares
String.prototype.replaceAll = function(search, replacement) {
var target = this;
return target.replace(new RegExp(search, 'g'), replacement);
};
Implementación de dividir y unir (funcional)
String.prototype.replaceAll = function(search, replacement) {
var target = this;
return target.split(search).join(replacement);
};
Sin saber demasiado sobre cómo funcionan las expresiones regulares detrás de escena en términos de eficiencia, en el pasado tendía a inclinarme hacia la implementación de división y unión sin pensar en el rendimiento. Cuando me pregunté cuál era más eficiente y por qué margen, lo usé como excusa para averiguarlo.
En mi máquina Chrome Windows 8, la implementación basada en expresiones regulares es la más rápida , mientras que la implementación de división y unión es un 53 % más lenta . Lo que significa que las expresiones regulares son dos veces más rápidas que la entrada de lorem ipsum que utilicé.
Consulte este punto de referencia que compara estas dos implementaciones entre sí.
Como se indica en el comentario a continuación de @ThomasLeduc y otros, podría haber un problema con la implementación basada en expresiones regulares si search
contiene ciertos caracteres que están reservados como caracteres especiales en expresiones regulares . La implementación supone que la persona que llama escapará de la cadena de antemano o solo pasará cadenas que no tengan los caracteres de 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 estuviera estandarizado como RegExp.escape(str)
, pero lamentablemente no existe:
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
}
Podríamos llamar escapeRegExp
dentro de nuestra String.prototype.replaceAll
implementación, sin embargo, no estoy seguro de cuánto afectará esto al rendimiento (potencialmente incluso para cadenas para las que no se necesita el escape, como todas las cadenas alfanuméricas).
En las últimas versiones de los navegadores más populares, puede utilizar replaceAll
como se muestra aquí:
let result = "1 abc 2 abc 3".replaceAll("abc", "xyz");
// `result` is "1 xyz 2 xyz 3"
Pero primero verifique ¿ Puedo usar u otra tabla de compatibilidad para asegurarse de que los navegadores a los que se dirige tengan soporte agregado para ello primero?
Para Node.js y compatibilidad con navegadores antiguos/no actuales:
Nota: No utilice la siguiente solución en código crítico para el rendimiento.
Como alternativa a las expresiones regulares para una cadena literal simple, puede usar
str = "Test abc test test abc test...".split("abc").join("");
El patrón general es
str.split(search).join(replacement)
Esto solía ser más rápido en algunos casos que usar replaceAll
una expresión regular, pero ya no parece ser el caso en los navegadores modernos.
Punto de referencia: https://jsben.ch/TZYzj
Conclusión:
Si tiene un caso de uso crítico para el rendimiento (por ejemplo, procesar cientos de cadenas), utilice el método de expresión regular. Pero para la mayoría de los casos de uso típicos, vale la pena no tener que preocuparse por los caracteres especiales.