Como substituo um caractere em um índice específico em JavaScript?

544

Eu tenho uma string, digamos, Hello worlde preciso substituir o caractere no índice 3. Como posso substituir um caracter especificando um índice?

var str = "hello world";

Eu preciso de algo como

str.replaceAt(0,"h");
Santhosh
fonte
131
O que é estranho é que str[0] = 'x'não parece gerar nenhum erro, mas ainda não tem o efeito desejado!
Michael
6
@ Michael com isso, você obteria o índice em 0, defina-o como 'x', essa declaração retornaria o novo valor; 'x'. mas tudo isso não muda o original, portanto é perfeitamente válido, mas não exatamente o que você esperava. não é uma referência
Paul Scheltema
8
@ Michael ele se "use strict"é ativado: Uncaught TypeError: Cannot assign to read only property '0' of string 'hello world'(pelo menos em navegadores WebKit)
Jan Turon
1
As strings Javascript são imutáveis, não podem ser modificadas "no local", portanto você não pode modificar um único caractere. de fato, toda ocorrência da mesma string é UM objeto.
Martijn Scheffer
ok, veja a resposta: D
Martijn Scheffer

Respostas:

611

Em JavaScript, as strings são imutáveis , o que significa que o melhor que você pode fazer é criar uma nova string com o conteúdo alterado e designar a variável para apontar para ela.

Você precisará definir a replaceAt()função você mesmo:

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

E use-o assim:

var hello = "Hello World";
alert(hello.replaceAt(2, "!!")); // Should display He!!o World
Cem Kalyoncu
fonte
101
Observe que geralmente não é uma boa idéia estender as classes JavaScript básicas. Use uma função de utilidade simples.
Ates Goral 16/09/09
86
Devo perguntar por que? O suporte ao protótipo existe para esse fim.
Cem Kalyoncu 16/09/09
30
@CemKalyoncu: Pode fazer com que o código seja ruim com outras bibliotecas. Mas eu nunca fui mordido por isso.
alex
6
@ alex: você está certo sobre isso, você realmente precisa verificar se essa função existe antes de fazê-lo. Mas, mesmo assim, deve fazer exatamente a mesma operação.
Cem Kalyoncu 21/07
80
Eu discordo, mesmo se você detectar se a função existe, uma biblioteca posterior ainda poderá usar / criar uma função semelhante - duas idéias ruins, tornando a pior. Em geral, nunca brinque com o código de outras pessoas (inclua o sistema principal). Crie uma nova função.
Martyman
93

Não há replaceAtfunção no JavaScript. Você pode usar o código a seguir para substituir qualquer caractere em qualquer sequência na posição 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
fonte
Eu prefiro esta solução porque você pode substituir um único caractere por ela. A solução com mais votos positivos não funciona se você deseja substituir apenas um caractere. Só funciona ao substituir dois caracteres! Além disso, substr deve ser substituído por substring, conforme mencionado em muitos outros comentários.
gignu 14/01
74

Você não pode. Pegue os caracteres antes e depois da posição e concorde em uma nova sequência:

var s = "Hello world";
var index = 3;
s = s.substring(0, index) + 'x' + s.substring(index + 1);
Guffa
fonte
Na verdade, sim, você pode, mas seria um exagero. Você pode configurar uma expressão regular para pular o primeiro índice - 1 caracteres e corresponder ao caractere no índice. Você pode usar String.replace com essa expressão regular para fazer uma substituição direta no local. Mas é um exagero. Então, na prática, você não pode. Mas, em teoria, você pode.
Ates Goral 16/09/09
12
@ Ates: A função de substituição não faz uma substituição no local, cria uma nova string e a retorna.
Guffa 16/09/09
2
MDN sugere usar String.prototype.substringmais String.prototype.substr.
Mikemike
33

Há muitas respostas aqui, e todas elas são baseadas em dois métodos:

  • MÉTODO1: divida a string usando duas substrings e encha o caractere entre elas
  • MÉTODO2: converte a cadeia de caracteres em matriz de caracteres, substitua um membro da matriz e junte-se a ela

Pessoalmente, eu usaria esses dois métodos em casos diferentes. Deixe-me explicar.

@FabioPhms: Seu método foi o que eu usei inicialmente e eu tinha medo de que ele seja ruim na string com muitos caracteres. No entanto, a pergunta é o que há em muitos personagens? Eu testei em 10 parágrafos "lorem ipsum" e demorou alguns milissegundos. Depois testei-o em cordas 10 vezes maiores - não havia realmente nenhuma grande diferença. Hum.

@vsync, @Cory Mawhorter: Seus comentários são inequívocos; no entanto, novamente, o que é uma string grande? Concordo que, para 32 ... 100kb, o desempenho deve ser melhor e deve-se usar a variante de substring para esta operação de substituição de caracteres.

Mas o que acontecerá se eu tiver que fazer algumas substituições?

Eu precisava realizar meus próprios testes para provar o que é mais rápido nesse caso. Digamos que tenhamos um algoritmo que manipulará uma cadeia relativamente curta que consiste em 1.000 caracteres. Esperamos que, em média, cada caractere dessa sequência seja substituído ~ 100 vezes. Portanto, o código para testar algo como isto é:

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

Eu criei um violino para isso, e está aqui . Existem dois testes, TEST1 (substring) e TEST2 (conversão de matriz).

Resultados:

  • TEST1: 195ms
  • TEST2: 6ms

Parece que a conversão de array supera a substring em 2 ordens de magnitude! Então - o que diabos aconteceu aqui ???

O que realmente acontece é que todas as operações no TEST2 são feitas no próprio array, usando a expressão de atribuição like strarr2[p] = n. A atribuição é realmente rápida em comparação com a substring em uma string grande, e é claro que ela vai ganhar.

Portanto, trata-se de escolher a ferramenta certa para o trabalho. Novamente.

OzrenTkalcecKrznaric
fonte
7
Movi seu teste para jsperf, com resultados muito diferentes: jsperf.com/string-replace-character . É tudo sobre como escolher a ferramenta certa para o trabalho;)
colllin
1
@ Colllin: Eu concordo absolutamente. Então, quase literalmente clonei os testes de jsfiddle para jsperf. No entanto, além de usar a ferramenta certa, você deve fazê-lo da maneira certa. Preste atenção ao problema, estamos falando sobre o que acontecerá se precisarmos fazer algumas substituições em um algoritmo. O exemplo concreto inclui 10000 substituições. Isso significa que um teste deve incluir 10000 substituições. Portanto, usando jsperf, obtive resultados bastante consistentes, consulte: jsperf.com/… .
OzrenTkalcecKrznaric
1
é por isso que eu não gosto de javascript. casos de uso freqüentes, intuitivos e óbvios não são provisionados. Você pensaria que os escritores de javascript pensariam que as pessoas podem querer substituir caracteres dentro de cadeias de caracteres e que decidem colocar métodos de conveniência no idioma.
ahnbizcad
1
@colllin fez algo diferente de OzrenTkalcecKrznaric. OzrenTkalcecKrznaric assumiu que a sequência é estática e que a divisão pode ser otimizada antes das execuções. O que não é necessariamente verdade. se você precisar dividir a cada execução, a abordagem de substring será cerca de duas vezes 4x mais rápida em cadeias pequenas, e apenas mais rápida quanto maior a cadeia. Na minha opinião, isso torna a substring a melhor implementação para a maioria dos casos de uso, impedindo um grande número de alterações em uma grande string estática.
WiR3D 02/03
3
O problema é que, no teste2, a divisão e a junção estão fora do loop for, onde você compara a substituição de um único caractere por um múltiplo (injusto), o primeiro método é mais rápido para substituições simples e o segundo é melhor para substituições encadeadas, uma após a outra
Θεόφιλος Μουρατίδης
32

Trabalhar com vetores geralmente é mais eficaz para entrar em contato com String.

Sugiro a seguinte função:

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

Execute este trecho:

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
fonte
9
isso é ruim para as grandes cadeias, não há necessidade de criar uma matriz com quantidade louca de células se você pode apenas usar substr para cortá-la ...
vsync
1
Útil se você precisar alterar muitos caracteres, e é simples.
Sheepy
6
Criei um teste no jsperf: jsperf.com/replace-character-by-index - O Substr é muito mais rápido e consistente, de 32 bytes a 100 kb. Votei isso de maneira positiva e, por mais que me doa dizer, mesmo que isso pareça mais agradável, o substr é a melhor escolha para strings de qualquer tamanho.
Cory Mawhorter
Isso é bastante desagradável.
Radko Dinev
Esta é uma boa solução rápida, se você sabe que vai usar pequenas seqüências de caracteres. Se você está bem com estender os protótipos, então você poderia alcançar comportamento similar em 2 linhas:Array.prototype.replace = function(index, val) { this[index] = val; return this; }; 'word'.split('').replace(1, '0').join(''); // returns 'w0rd'
Michael Plautz
29

No Javascript, as strings são imutáveis, então você precisa fazer algo como

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

Para substituir o caractere em x em i por 'h'

DevDevDev
fonte
28
str = str.split('');
str[3] = 'h';
str = str.join('');
colllin
fonte
4
Clara e simples, mas atualmente não funcionará com emoji (como 😀) ao usar splitejoin
Verde
1
Com es6, acho que Array.from (str) pode ser uma opção melhor agora, mas vim aqui com esse conhecimento e aprendi algo tão conciso com você, então muito obrigado!
David Kamer 23/06
7

Uma linha usando String.replace com retorno de chamada (sem suporte a 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
fonte
6

Esse método é bom para seqüências de caracteres pequenas, mas pode ser lento para textos maiores.

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
fonte
3

@CemKalyoncu: Obrigado pela ótima resposta!

Também o adaptei um pouco para torná-lo mais parecido com o método Array.splice (e levei em consideração a nota do @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
fonte
Não sei por que isso foi rejeitado. É uma resposta legítima. Funciona como indicado. E é consistente com a Array.splicefuncionalidade de tipo.
Scrimothy
3

Isso funciona de maneira semelhante a Array.splice:

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

Você poderia tentar

var strArr = str.split("");

strArr[0] = 'h';

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

Se você deseja substituir caracteres na cadeia, crie cadeias mutáveis. Essas são essencialmente matrizes de caracteres. Você pode criar uma fábrica:

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

Em seguida, você pode acessar os caracteres e toda a matriz é convertida em string quando usada como string:

  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ň
fonte
2

Generalizando a resposta de Afanasii Kurakin, temos:

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

Vamos expandir e explicar a expressão regular e a função substituta:

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

A expressão regular .corresponde exatamente a um caractere. O gfaz-lo coincidir com todos os personagens em um loop. A replacerfunção é chamada, dado o caractere original e o índice de onde esse caractere está na string. Fazemos uma ifdeclaração simples para determinar se vamos retornar um origCharou outro newChar.

Stephen Quan
fonte
2

Você pode estender o tipo de sequência para incluir o método de inserção:

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

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

Então você pode chamar a função:

mbadeveloper
fonte
1

Eu fiz uma função que faz algo semelhante ao que você pergunta, verifica se um caractere na string está em uma matriz de caracteres não permitidos, se é que o substitui por ''

    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
fonte
1

isso é facilmente possível com o 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
fonte
1

Aqui está uma versão que eu criei se você quiser estilizar palavras ou caracteres individuais no índice em react / javascript.

replaceAt( yourArrayOfIndexes, yourString/orArrayOfStrings ) 

Exemplo de trabalho: https://codesandbox.io/s/ov7zxp9mjq

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

E aqui está outro 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('');
}

E outro...

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
fonte
0

Eu sei que isso é antigo, mas a solução não funciona para o índice negativo, então adiciono um patch a ele. espero que ajude alguém

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
fonte
0

Digamos que você deseja substituir o Kthíndice (índice baseado em 0) por 'Z'. Você poderia usar Regexpara fazer isso.

var re = var re = new RegExp("((.){" + K + "})((.){1})")
str.replace(re, "$1A$`");
ksp
fonte
Alguma idéia de por que isso está marcado não é útil?
Ksp
Eu não verifiquei se esse regex funciona, mas talvez ele tenha diminuído o voto porque provavelmente é muito mais rápido criar uma nova string do que compilar uma máquina de estado (expressão regular), que é muito cara.
Felo Vilches
0

Você pode usar a seguinte função para substituir Characterou Stringem uma posição específica de uma String. Para substituir todos os casos de correspondência a seguir, use a String.prototype.replaceAllMatches()função

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

Teste:

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

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

Resultado:

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

Aqui está minha solução usando o operador ternário e de mapa. Final mais legível e de fácil manutenção, mais fácil de entender, se você me perguntar.

É mais sobre es6 e melhores práticas.

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
fonte
-3

Os métodos aqui são complicados. Eu faria assim:

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

Isto é o mais simples possível.

mikey
fonte
6
Na verdade não. De fato, substituirá a primeira ocorrência do personagem. Ainda errado.
Tomáš Zato - Restabelece Monica