Búsqueda de sitios web

javascript - Método más rápido para reemplazar todas las instancias de un carácter en una cadena


¿Cuál es la forma más rápida de reemplazar todas las instancias de una cadena/caracter en una cadena en JavaScript? ¿Un while, un bucle for, o una expresión regular?

Respuesta #1

Lo más fácil sería usar una expresión regular con la bandera g para reemplazar todas las instancias:

str.replace(/foo/g, "bar")

Esto reemplazará todas las apariciones de foo con bar en la cadena str. Si solo tienes una cadena, puedes convertirla en un objeto RegExp así:

var pattern = "foobar",
    re = new RegExp(pattern, "g");

Respuesta #2

Prueba este replaceAll: http://dumpsite.com/forum/index.php?topic=4.msg8#msg8

String.prototype.replaceAll = function(str1, str2, ignore) 
{
    return this.replace(new RegExp(str1.replace(/([\/\,\!"^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g,"\\$&"),(ignore?"gi":"g")),(typeof(str2)=="string")?str2.replace(/\$/g,"$$$$"):str2);
} 

Es muy rápido, y funcionará para TODAS estas condiciones en las que muchos otros fallan:

"x".replaceAll("x", "xyz");
// xyz

"x".replaceAll("", "xyz");
// xyzxxyz

"aA".replaceAll("a", "b", true);
// bb

"Hello???".replaceAll("?", "!");
// Hello!!!

Hazme saber si puedes romperlo, o si tienes algo mejor, pero asegúrate de que pueda pasar estas 4 pruebas.

Respuesta #3

var mystring = 'This is a string';
var newString = mystring.replace(/i/g, "a");

console.log(newString);

newString ahora es 'Thas as a strang'

Respuesta #4

También puedes probar:

string.split('foo').join('bar');

Respuesta #5

Puedes usar lo siguiente:

newStr = str.replace(/[^a-z0-9]/gi, '_');

o

newStr = str.replace(/[^a-zA-Z0-9]/g, '_');

Esto va a reemplazar todos los caracteres que no sean letras o números por ('_'). Simplemente cambie el valor del guion bajo por lo que quiera reemplazar.

Respuesta #6

Usa el objeto Regex así

var regex=new RegExp('"', 'g'); str=str.replace(regex, '\'');

Reemplazará todas las ocurrencias de " por '.

Respuesta #7

Solo pensando en ello desde el punto de vista de la velocidad, creo que el ejemplo con distinción entre mayúsculas y minúsculas proporcionado en el enlace de arriba sería con mucho la solución más rápida.

var token = "\r\n";
var newToken = " ";
var oldStr = "This is a test\r\nof the emergency broadcasting\r\nsystem.";
newStr = oldStr.split(token).join(newToken);

newStr sería "Esto es una prueba del sistema de transmisión de emergencia."

Respuesta #8

Creo que la verdadera respuesta es que depende completamente de cómo sean tus entradas. Creé un JsFiddle para probar un montón de estos y un par de los míos contra varias entradas. No importa cómo mire los resultados, no veo un ganador claro.

  • RegExp no fue el más rápido en ninguno de los casos de prueba, pero tampoco fue malo.
  • El enfoque de Dividir/Unir parece más rápido para reemplazos escasos.
  • Este que escribí parece el más rápido para entradas pequeñas y reemplazos densos:

    function replaceAllOneCharAtATime(inSource, inToReplace, inReplaceWith) {
        var output="";
        var firstReplaceCompareCharacter = inToReplace.charAt(0);
        var sourceLength = inSource.length;
        var replaceLengthMinusOne = inToReplace.length - 1;
        for(var i = 0; i < sourceLength; i++){
            var currentCharacter = inSource.charAt(i);
            var compareIndex = i;
            var replaceIndex = 0;
            var sourceCompareCharacter = currentCharacter;
            var replaceCompareCharacter = firstReplaceCompareCharacter;
            while(true){
                if(sourceCompareCharacter != replaceCompareCharacter){
                output += currentCharacter;
                break;
            }
            if(replaceIndex >= replaceLengthMinusOne) {
                i+=replaceLengthMinusOne;
                output += inReplaceWith;
                //was a match
                break;
            }
            compareIndex++; replaceIndex++;
            if(i >= sourceLength){
                // not a match
                break;
            }
            sourceCompareCharacter = inSource.charAt(compareIndex)
                replaceCompareCharacter = inToReplace.charAt(replaceIndex);
            }   
            replaceCompareCharacter += currentCharacter;
        }
        return output;
    }
    

Respuesta #9

Acabo de programar un benchmark y probar las tres primeras respuestas. Parece que para cadenas cortas (<500 caracteres) la tercera respuesta más votada es más rápida que la segunda más votada.

Para cadenas largas (agrega ".repeat(300)" a la cadena de prueba) el más rápido es la respuesta 1 seguido por la segunda y la tercera.

Nota:

Lo anterior es cierto para los navegadores que usan el motor v8 (chrome/chromium, etc).
Con firefox (motor SpiderMonkey) los resultados son totalmente diferentes
¡Comprúbenlo ustedes mismos!! Firefox con la tercera solución parece ser
más de 4.5 veces más rápido que Chrome con la primera solución... una locura :D

function log(data) {
  document.getElementById("log").textContent += data + "\n";
}

benchmark = (() => {

  time_function = function(ms, f, num) {
    var z;
    var t = new Date().getTime();
    for (z = 0;
      ((new Date().getTime() - t) < ms); z++) f(num);
    return (z / ms)
  } // returns how many times the function was run in "ms" milliseconds.


  function benchmark() {
    function compare(a, b) {
      if (a[1] > b[1]) {
        return -1;
      }
      if (a[1] < b[1]) {
        return 1;
      }
      return 0;
    }

    // functions

    function replace1(s) {
      s.replace(/foo/g, "bar")
    }

String.prototype.replaceAll2 = function(_f, _r){ 

  var o = this.toString();
  var r = '';
  var s = o;
  var b = 0;
  var e = -1;
//      if(_c){ _f = _f.toLowerCase(); s = o.toLowerCase(); }

  while((e=s.indexOf(_f)) > -1)
  {
    r += o.substring(b, b+e) + _r;
    s = s.substring(e+_f.length, s.length);
    b += e+_f.length;
  }

  // Add Leftover
  if(s.length>0){ r+=o.substring(o.length-s.length, o.length); }

  // Return New String
  return r;
};

String.prototype.replaceAll = function(str1, str2, ignore) {
      return this.replace(new RegExp(str1.replace(/([\/\,\!"^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g, "\\$&"), (ignore ? "gi" : "g")), (typeof(str2) == "string") ? str2.replace(/\$/g, "$$$$") : str2);
    }

    function replace2(s) {
      s.replaceAll("foo", "bar")
    }

    function replace3(s) {
      s.split('foo').join('bar');
    }

    function replace4(s) {
      s.replaceAll2("foo", "bar")
    }


    funcs = [
      [replace1, 0],
      [replace2, 0],
      [replace3, 0],
      [replace4, 0]
    ];

    funcs.forEach((ff) => {
      console.log("Benchmarking: " + ff[0].name);
      ff[1] = time_function(2500, ff[0], "foOfoobarBaR barbarfoobarf00".repeat(10));
      console.log("Score: " + ff[1]);

    })
    return funcs.sort(compare);
  }

  return benchmark;
})()
log("Starting benchmark...\n");
res = benchmark();
console.log("Winner: " + res[0][0].name + " !!!");
count = 1;
res.forEach((r) => {
  log((count++) + ". " + r[0].name + " score: " + Math.floor(10000 * r[1] / res[0][1]) / 100 + ((count == 2) ? "% *winner*" : "% speed of winner.") + " (" + Math.round(r[1] * 100) / 100 + ")");
});
log("\nWinner code:\n");
log(res[0][0].toString());
<textarea rows="50" cols="80" style="font-size: 16; resize:none; border: none;" id="log"></textarea>

La prueba se ejecutará durante 10 s (+2 s) mientras haces clic en el botón.

Mis resultados (en la misma computadora):

Chrome/Linux Ubuntu 64:
1. replace1 score: 100% *winner* (766.18)
2. replace4 score: 99.07% speed of winner. (759.11)
3. replace3 score: 68.36% speed of winner. (523.83)
4. replace2 score: 59.35% speed of winner. (454.78)

Firefox/Linux Ubuntu 64
1. replace3 score: 100% *winner* (3480.1)
2. replace1 score: 13.06% speed of winner. (454.83)
3. replace4 score: 9.4% speed of winner. (327.42)
4. replace2 score: 4.81% speed of winner. (167.46)

Buen lío, ¿eh?

Me tomé la libertad de añadir más resultados de pruebas

Chrome/Windows 10
1. replace1 score: 100% *winner* (742.49)
2. replace4 score: 85.58% speed of winner. (635.44)
3. replace2 score: 54.42% speed of winner. (404.08)
4. replace3 score: 50.06% speed of winner. (371.73)

Firefox/Windows 10
1. replace3 score: 100% *winner* (2645.18)
2. replace1 score: 30.77% speed of winner. (814.18)
3. replace4 score: 22.3% speed of winner. (589.97)
4. replace2 score: 12.51% speed of winner. (331.13)

Edge/Windows 10
1. replace1 score: 100% *winner* (1251.24)
2. replace2 score: 46.63% speed of winner. (583.47)
3. replace3 score: 44.42% speed of winner. (555.92)
4. replace4 score: 20% speed of winner. (250.28)

Chrome en Galaxy Note 4

1. replace4 score: 100% *winner* (99.82)
2. replace1 score: 91.04% speed of winner. (90.88)
3. replace3 score: 70.27% speed of winner. (70.15)
4. replace2 score: 38.25% speed of winner. (38.18)

Artículos relacionados