¿Cómo reemplazo un carácter en un índice particular en JavaScript?

544

Tengo una cadena, digamos, Hello worldy necesito reemplazar el carácter en el índice 3. ¿Cómo puedo reemplazar un carácter especificando un índice?

var str = "hello world";

Necesito algo como

str.replaceAt(0,"h");
Santhosh
fuente
131
Lo extraño es que str[0] = 'x'no parece arrojar ningún error, ¡pero no tiene el efecto deseado!
Michael
66
@Michael con eso obtendría el índice en 0, configúrelo en 'x', esa declaración en sí misma devolvería el nuevo valor; 'X'. pero todo esto no cambia el original, por lo que es perfectamente válido, simplemente no es lo que esperaba. no es una referencia
Paul Scheltema
8
@Michael lo hace si "use strict"está activado: Uncaught TypeError: Cannot assign to read only property '0' of string 'hello world'(al menos en los navegadores webkit)
Jan Turoň
1
Las cadenas de Javascript son inmutables, no pueden modificarse "en su lugar", por lo que no puede modificar un solo carácter. de hecho cada ocurrencia de la misma cadena es UN objeto.
Martijn Scheffer,
ok, mira la respuesta: D
Martijn Scheffer

Respuestas:

611

En JavaScript, las cadenas son inmutables , lo que significa que lo mejor que puede hacer es crear una nueva cadena con el contenido modificado y asignar la variable para que apunte a ella.

Tendrá que definir la replaceAt()función usted mismo:

String.prototype.replaceAt = function(index, replacement) {
    return this.substr(0, index) + replacement + this.substr(index + replacement.length);
}

Y úsalo así:

var hello = "Hello World";
alert(hello.replaceAt(2, "!!")); // Should display He!!o World
Cem Kalyoncu
fuente
101
Tenga en cuenta que, en general, no es una buena idea extender las clases de JavaScript base. Utilice una función de utilidad simple en su lugar.
Ates Goral
86
Debo preguntar por qué? El soporte prototipo está ahí para este propósito.
Cem Kalyoncu
30
@CemKalyoncu: puede hacer que el código juegue mal con otras bibliotecas. Pero nunca me ha picado eso.
alex
66
@alex: tienes razón en eso, realmente necesitas verificar si esa función existe antes de hacerlo. Pero aún así, si lo hace, debería hacer exactamente la misma operación.
Cem Kalyoncu
80
No estoy de acuerdo, incluso si detecta si la función existe, una biblioteca posterior aún puede usar / crear una función similar: 2 ideas malas que empeoran. En general, nunca juegues con el código de otras personas (incluye el sistema central). Crea una nueva función.
Martyman
93

No hay replaceAtfunción en JavaScript. Puede usar el siguiente código para reemplazar cualquier carácter en cualquier cadena en la posición especificada:

function rep() {
    var str = 'Hello World';
    str = setCharAt(str,4,'a');
    alert(str);
}

function setCharAt(str,index,chr) {
    if(index > str.length-1) return str;
    return str.substr(0,index) + chr + str.substr(index+1);
}
<button onclick="rep();">click</button>

rahul
fuente
Prefiero esta solución porque puedes reemplazar un solo personaje con ella. La solución que tiene la mayoría de los votos positivos no funciona si desea reemplazar solo un personaje. ¡Solo funciona cuando se reemplazan dos caracteres! Además, substr debe reemplazarse por substring como se menciona en muchos otros comentarios.
Gignu
74

No puedes Tome los caracteres antes y después de la posición y concat en una nueva cadena:

var s = "Hello world";
var index = 3;
s = s.substring(0, index) + 'x' + s.substring(index + 1);
Guffa
fuente
En realidad, sí, puedes, pero sería una exageración. Puede configurar una expresión regular para omitir el primer índice: 1 caracteres y hacer coincidir el carácter en el índice. Puede usar String.replace con esa expresión regular para hacer un reemplazo directo en el lugar. Pero es una exageración. Entonces, en la práctica no puedes. Pero en teoría, puedes.
Ates Goral
12
@Ates: la función de reemplazo no hace un reemplazo en el lugar, crea una nueva cadena y la devuelve.
Guffa
2
MDN sugiere usar String.prototype.substringmás String.prototype.substr.
Mikemike
33

Aquí hay muchas respuestas, y todas se basan en dos métodos:

  • MÉTODO1: divide la cadena usando dos subcadenas y rellena el carácter entre ellas
  • MÉTODO2: convierta la cadena en una matriz de caracteres, reemplace un miembro de la matriz y únase a él

Personalmente, usaría estos dos métodos en diferentes casos. Dejame explicar.

@FabioPhms: Su método fue el que usé inicialmente y tenía miedo de que sea malo en una cadena con muchos caracteres. Sin embargo, la pregunta es ¿qué hay muchos personajes? Lo probé en 10 párrafos "lorem ipsum" y me llevó unos milisegundos. Luego lo probé en una cadena 10 veces más grande, realmente no había gran diferencia. Hm.

@vsync, @Cory Mawhorter: sus comentarios no son ambiguos; sin embargo, de nuevo, ¿qué es una cadena grande? Estoy de acuerdo en que para 32 ... 100kb el rendimiento debería ser mejor y uno debería usar la variante de subcadena para esta operación de reemplazo de caracteres.

Pero, ¿qué sucederá si tengo que hacer bastantes reemplazos?

Necesitaba realizar mis propias pruebas para probar qué es más rápido en ese caso. Digamos que tenemos un algoritmo que manipulará una cadena relativamente corta que consta de 1000 caracteres. Esperamos que en promedio cada carácter en esa cadena sea reemplazado ~ 100 veces. Entonces, el código para probar algo como esto es:

var str = "... {A LARGE STRING HERE} ...";

for(var i=0; i<100000; i++)
{
  var n = '' + Math.floor(Math.random() * 10);
  var p = Math.floor(Math.random() * 1000);
  // replace character *n* on position *p*
}

Creé un violín para esto, y está aquí . Hay dos pruebas, TEST1 (subcadena) y TEST2 (conversión de matriz).

Resultados:

  • PRUEBA1: 195ms
  • PRUEBA2: 6 ms

¡Parece que la conversión de matriz supera a la subcadena en 2 órdenes de magnitud! Entonces, ¿qué demonios pasó aquí?

Lo que sucede en realidad es que todas las operaciones en TEST2 se realizan en la matriz misma, utilizando expresiones de asignación como strarr2[p] = n. La asignación es realmente rápida en comparación con la subcadena en una cadena grande, y está claro que va a ganar.

Entonces, se trata de elegir la herramienta adecuada para el trabajo. De nuevo.

OzrenTkalcecKrznaric
fuente
77
Trasladó su prueba a jsperf, con resultados muy diferentes: jsperf.com/string-replace-character . Se trata de elegir la herramienta adecuada para el trabajo;)
colllin
1
@colllin: estoy totalmente de acuerdo. Así que literalmente cloné las pruebas de jsfiddle a jsperf. Sin embargo, aparte de usar la herramienta correcta, debe hacerlo de la manera correcta. Preste atención al problema, estamos hablando de lo que sucederá si tenemos que hacer bastantes reemplazos en un algoritmo. El ejemplo concreto incluye 10000 reemplazos. Esto significa que una prueba debe incluir 10000 reemplazos. Entonces, usando jsperf, obtuve resultados bastante consistentes, ver: jsperf.com/… .
OzrenTkalcecKrznaric
1
Por eso no me gusta JavaScript. estos casos de uso frecuentes, intuitivos y obvios no están previstos. Uno pensaría que se les ocurriría a los escritores de javascript que las personas podrían querer sustituir los caracteres dentro de las cadenas, y que decidirían poner métodos convenientes en el lenguaje.
ahnbizcad
1
@colllin hizo algo diferente a OzrenTkalcecKrznaric. OzrenTkalcecKrznaric asumió que la cadena es estática y que la división se puede optimizar antes de las ejecuciones. Lo cual no es necesariamente cierto. si tiene que dividirse en cada ejecución, entonces el enfoque de subcadena es aproximadamente dos veces 4 veces más rápido en cadenas pequeñas, y solo más rápido cuanto más grande sea la cadena. En mi opinión, esto hace que la subcadena sea la mejor implementación para la mayoría de los casos de uso, salvo grandes cantidades de cambios en una cadena estática grande.
WiR3D
3
El problema es que en test2, la división y la unión están fuera del ciclo for, donde se compara el reemplazo de un solo carácter con uno múltiple (injusto), el primer método es más rápido para los reemplazos individuales y el segundo es mejor para los reemplazos encadenados uno tras otro
Θεόφιλος Μουρατίδης
32

El trabajo con vectores suele ser más efectivo para contactar con String.

Sugiero la siguiente función:

String.prototype.replaceAt=function(index, char) {
    var a = this.split("");
    a[index] = char;
    return a.join("");
}

Ejecute este fragmento:

String.prototype.replaceAt=function(index, char) {
    var a = this.split("");
    a[index] = char;
    return a.join("");
}

var str = "hello world";
str = str.replaceAt(3, "#");

document.write(str);

Fabio Phms
fuente
99
esto es malo para cadenas grandes, no es necesario crear una matriz con una cantidad loca de celdas si solo puede usar substr para cortarlo ...
vsync
1
Útil si necesita cambiar muchos caracteres, y es simple.
Sheepy
66
Creé una prueba en jsperf: jsperf.com/replace-character-by-index - Substr es mucho más rápido y consistente desde 32bytes hasta 100kb. Voté esto y, por mucho que me duela decirlo, a pesar de que esto se siente mejor, substr es la mejor opción para cuerdas de cualquier tamaño.
Cory Mawhorter
Esto es bastante poco óptimo.
Radko Dinev
Esta es una buena solución rápida si sabe que va a utilizar cadenas pequeñas. Si está de acuerdo con extender los prototipos, entonces podría lograr un comportamiento similar en 2 líneas:Array.prototype.replace = function(index, val) { this[index] = val; return this; }; 'word'.split('').replace(1, '0').join(''); // returns 'w0rd'
Michael Plautz
29

En Javascript, las cadenas son inmutables, por lo que debe hacer algo como

var x = "Hello world"
x = x.substring(0, i) + 'h' + x.substring(i+1);

Para reemplazar el carácter en x en i con 'h'

DevDevDev
fuente
28
str = str.split('');
str[3] = 'h';
str = str.join('');
colllin
fuente
44
Claro y simple, pero actualmente no funcionará con emoji (como 😀) cuando se usa splityjoin
Verde
1
Con es6, creo que Array.from (str) podría ser una mejor opción ahora, pero vine aquí con ese conocimiento y aprendí algo tan conciso de usted, ¡así que gracias!
David Kamer
7

One-liner usando String.replace con devolución de llamada (sin soporte de emoji):

// 0 - index to replace, 'f' - replacement string
'dog'.replace(/./g, (c, i) => i == 0? 'f': c)
// "fog"

Explicado:

//String.replace will call the callback on each pattern match
//in this case - each character
'dog'.replace(/./g, function (character, index) {
   if (index == 0) //we want to replace the first character
     return 'f'
   return character //leaving other characters the same
})
Afanasii Kurakin
fuente
6

Este método es bueno para cadenas de longitud pequeña, pero puede ser lento para texto más grande.

var x = "White Dog";
var arr = x.split(""); // ["W", "h", "i", "t", "e", " ", "D", "o", "g"]
arr.splice(6, 1, 'F');
var result = arr.join(""); // "White Fog"

/* 
  Here 6 is starting index and 1 is no. of array elements to remove and 
  final argument 'F' is the new character to be inserted. 
*/
Vikramaditya
fuente
3

@CemKalyoncu: ¡Gracias por la excelente respuesta!

También lo adapté un poco para hacerlo más parecido al método Array.splice (y tomé en cuenta la nota de @Ates):

spliceString=function(string, index, numToDelete, char) {
      return string.substr(0, index) + char + string.substr(index+numToDelete);
   }

var myString="hello world!";
spliceString(myString,myString.lastIndexOf('l'),2,'mhole'); // "hello wormhole!"
Scrimothy
fuente
No estoy seguro de por qué esto fue rechazado. Es una respuesta legítima. Funciona como se indica. Y es consistente con la Array.splicefuncionalidad de tipo.
Scrimothy
3

Esto funciona de manera similar a Array.splice:

String.prototype.splice = function (i, j, str) {
    return this.substr(0, i) + str + this.substr(j, this.length);
};
Aram Kocharyan
fuente
3

Tu podrías intentar

var strArr = str.split("");

strArr[0] = 'h';

str = strArr.join("");
Mehulkumar
fuente
2

Si desea reemplazar caracteres en una cadena, debe crear cadenas mutables. Estos son esencialmente matrices de caracteres. Podrías crear una fábrica:

  function MutableString(str) {
    var result = str.split("");
    result.toString = function() {
      return this.join("");
    }
    return result;
  }

Luego puede acceder a los caracteres y toda la matriz se convierte en cadena cuando se usa como cadena:

  var x = MutableString("Hello");
  x[0] = "B"; // yes, we can alter the character
  x.push("!"); // good performance: no new string is created
  var y = "Hi, "+x; // converted to string: "Hi, Bello!"
Jan Turoň
fuente
2

Generalizando la respuesta de Afanasii Kurakin, tenemos:

function replaceAt(str, index, ch) {
    return str.replace(/./g, (c, i) => i == index ? ch : c)
}

let str = 'Hello World'
str = replaceAt(str, 1, 'u')
console.log(str) // Hullo World

Expandamos y expliquemos tanto la expresión regular como la función de reemplazo:

function replaceAt(str, index, newChar) {
    function replacer(origChar, strIndex) {
        if (strIndex === index)
            return newChar
        else
            return origChar
    }
    return str.replace(/./g, replacer)
}

let str = 'Hello World'
str = replaceAt(str, 1, 'u')
console.log(str) // Hullo World

La expresión regular .coincide exactamente con un carácter. La ghace coincidir con cada personaje en un bucle for. La replacerfunción se llama dado el carácter original y el índice de dónde está ese carácter en la cadena. Hacemos una ifdeclaración simple para determinar si vamos a volver origCharo newChar.

Stephen Quan
fuente
2

Puede extender el tipo de cadena para incluir el método de inserción:

String.prototype.append = function (index,value) {
  return this.slice(0,index) + value + this.slice(index);
};

var s = "New string";
alert(s.append(4,"complete "));

Entonces puedes llamar a la función:

mbadeveloper
fuente
1

Hice una función que hace algo similar a lo que pides, comprueba si un carácter en cadena está en una matriz de caracteres no permitidos si lo reemplaza con ''

    var validate = function(value){
        var notAllowed = [";","_",">","<","'","%","$","&","/","|",":","=","*"];
        for(var i=0; i<value.length; i++){
            if(notAllowed.indexOf(value.charAt(i)) > -1){
               value = value.replace(value.charAt(i), "");
               value = validate(value);
            }
       }
      return value;
   }
mirzak
fuente
1

¡esto se puede lograr fácilmente con RegExp!

const str = 'Hello RegEx!';
const index = 11;
const replaceWith = 'p';

//'Hello RegEx!'.replace(/^(.{11})(.)/, `$1p`);
str.replace(new RegExp(`^(.{${ index }})(.)`), `$1${ replaceWith }`);

//< "Hello RegExp"
Madmadi
fuente
1

Aquí hay una versión que se me ocurrió si desea diseñar palabras o caracteres individuales en su índice en react / javascript.

replaceAt( yourArrayOfIndexes, yourString/orArrayOfStrings ) 

Ejemplo de trabajo: https://codesandbox.io/s/ov7zxp9mjq

function replaceAt(indexArray, [...string]) {
    const replaceValue = i => string[i] = <b>{string[i]}</b>;
    indexArray.forEach(replaceValue);
    return string;
}

Y aquí hay otro método alternativo.

function replaceAt(indexArray, [...string]) {
    const startTag = '<b>';
    const endTag = '</b>';
    const tagLetter = i => string.splice(i, 1, startTag + string[i] + endTag);
    indexArray.forEach(tagLetter);
    return string.join('');
}

Y otro...

function replaceAt(indexArray, [...string]) {
    for (let i = 0; i < indexArray.length; i++) {
        string = Object.assign(string, {
          [indexArray[i]]: <b>{string[indexArray[i]]}</b>
        });
    }
    return string;
}
Matt Wright
fuente
0

Sé que esto es antiguo, pero la solución no funciona para el índice negativo, así que le agrego un parche. espero que ayude a alguien

String.prototype.replaceAt=function(index, character) {
    if(index>-1) return this.substr(0, index) + character + this.substr(index+character.length);
    else return this.substr(0, this.length+index) + character + this.substr(index+character.length);

}
cesar moro
fuente
0

Digamos que desea reemplazar el Kthíndice (índice basado en 0) con 'Z'. Podrías Regexhacer esto.

var re = var re = new RegExp("((.){" + K + "})((.){1})")
str.replace(re, "$1A$`");
ksp
fuente
¿Alguna idea de por qué esta etiqueta no es útil?
ksp
No he comprobado si esta expresión regular funciona, pero tal vez se rechaza porque probablemente sea mucho más rápido crear una nueva cadena que compilar una máquina de estados (expresión regular), que es muy costosa.
Felo Vilches
0

Puede usar la siguiente función para reemplazar Charactero Stringen una posición particular de una Cadena. Para reemplazar todos los siguientes casos de coincidencia, utilice la String.prototype.replaceAllMatches()función.

String.prototype.replaceMatch = function(matchkey, replaceStr, matchIndex) {
    var retStr = this, repeatedIndex = 0;
    for (var x = 0; (matchkey != null) && (retStr.indexOf(matchkey) > -1); x++) {
        if (repeatedIndex == 0 && x == 0) {
            repeatedIndex = retStr.indexOf(matchkey);
        } else { // matchIndex > 0
            repeatedIndex = retStr.indexOf(matchkey, repeatedIndex + 1);
        }
        if (x == matchIndex) {
            retStr = retStr.substring(0, repeatedIndex) + replaceStr + retStr.substring(repeatedIndex + (matchkey.length));
            matchkey = null; // To break the loop.
        }
    }
    return retStr;
};

Prueba:

var str = "yash yas $dfdas.**";

console.log('Index Matched replace : ', str.replaceMatch('as', '*', 2) );
console.log('Index Matched replace : ', str.replaceMatch('y', '~', 1) );

Salida:

Index Matched replace :  yash yas $dfd*.**
Index Matched replace :  yash ~as $dfdas.**
Yash
fuente
-1

Aquí está mi solución usando el operador ternario y de mapa. Más legible, mantenible y más fácil de entender si me preguntas.

Está más en es6 y las mejores prácticas.

function replaceAt() {
  const replaceAt = document.getElementById('replaceAt').value;

  const str = 'ThisIsATestStringToReplaceCharAtSomePosition';
  const newStr = Array.from(str).map((character, charIndex) => charIndex === (replaceAt - 1) ? '' : character).join('');

  console.log(`New string: ${newStr}`);
}
<input type="number" id="replaceAt" min="1" max="44" oninput="replaceAt()"/>

karlo1zg
fuente
-3

Los métodos aquí son complicados. Lo haría de esta manera:

var myString = "this is my string";
myString = myString.replace(myString.charAt(number goes here), "insert replacement here");

Esto es tan simple como se pone.

mikey
fuente
66
No realmente. De hecho, reemplazará la primera aparición del personaje. Sigue siendo incorrecto.
Tomáš Zato - Restablece a Mónica el