Comment remplacer un caractère à un index particulier en JavaScript?

544

J'ai une chaîne, disons Hello worldet je dois remplacer le caractère à l'index 3. Comment puis-je remplacer un caractère en spécifiant un index?

var str = "hello world";

J'ai besoin de quelque chose comme

str.replaceAt(0,"h");
Santhosh
la source
131
Ce qui est bizarre, c'est que str[0] = 'x'cela ne semble pas générer d'erreurs, mais n'a pas l'effet souhaité!
Michael
6
@Michael avec cela vous obtiendrez l'index à 0, définissez-le sur 'x', cette instruction en elle-même retournerait la nouvelle valeur; 'X'. mais tout cela ne change pas l'originale, donc c'est parfaitement valable, tout simplement pas ce que vous attendiez. ce n'est pas une référence
Paul Scheltema
8
@Michael il le fait si "use strict"est activé: Uncaught TypeError: Cannot assign to read only property '0' of string 'hello world'(au moins dans les navigateurs
webkit
1
Les chaînes Javascript sont immuables, elles ne peuvent pas être modifiées "sur place" donc vous ne pouvez pas modifier un seul caractère. en fait, chaque occurrence de la même chaîne est UN objet.
Martijn Scheffer
ok, voir la réponse: D
Martijn Scheffer

Réponses:

611

En JavaScript, les chaînes sont immuables , ce qui signifie que le mieux que vous puissiez faire est de créer une nouvelle chaîne avec le contenu modifié et d'affecter la variable à la pointer.

Vous devrez définir la replaceAt()fonction vous-même:

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

Et utilisez-le comme ceci:

var hello = "Hello World";
alert(hello.replaceAt(2, "!!")); // Should display He!!o World
Cem Kalyoncu
la source
101
Notez que ce n'est généralement pas une bonne idée d'étendre les classes JavaScript de base. Utilisez plutôt une fonction utilitaire simple.
Ates Goral
86
Je dois demander pourquoi? Le support du prototype est là pour cela.
Cem Kalyoncu
30
@CemKalyoncu: Cela peut rendre le code mal joué avec d'autres bibliothèques. Mais je n'ai jamais été mordu par ça moi-même.
alex
6
@alex: vous avez raison, vous devez vraiment vérifier si cette fonction existe avant de la faire. Mais même si c'est le cas, il devrait faire exactement la même opération.
Cem Kalyoncu
80
Je ne suis pas d'accord, même si vous détectez si la fonction existe, une bibliothèque ultérieure peut toujours utiliser / créer une fonction similaire - 2 mauvaises idées qui en font une pire. En général, ne jouez jamais avec le code d'autres personnes (y compris le système de base). Créez une nouvelle fonction.
martyman
93

Il n'y a pas de replaceAtfonction en JavaScript. Vous pouvez utiliser le code suivant pour remplacer n'importe quel caractère dans n'importe quelle chaîne à la position spécifiée:

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
la source
Je préfère cette solution car vous pouvez remplacer un seul caractère par celle-ci. La solution qui a le plus de votes positifs ne fonctionne pas si vous souhaitez remplacer un seul caractère. Cela ne fonctionne que lors du remplacement de deux caractères! De plus, substr doit être remplacé par substring comme mentionné dans de nombreux autres commentaires.
gignu
74

Tu ne peux pas. Prenez les caractères avant et après la position et enchaînez dans une nouvelle chaîne:

var s = "Hello world";
var index = 3;
s = s.substring(0, index) + 'x' + s.substring(index + 1);
Guffa
la source
En fait, oui, vous le pouvez, mais ce serait exagéré. Vous pouvez configurer une expression régulière pour ignorer le premier index - 1 caractère et faire correspondre le caractère à l'index. Vous pouvez utiliser String.replace avec cette expression régulière pour effectuer un remplacement direct et sur place. Mais c'est exagéré. Donc, en pratique, vous ne pouvez pas. Mais en théorie, vous le pouvez.
Ates Goral
12
@Ates: La fonction replace ne fait pas de remplacement sur place, elle crée une nouvelle chaîne et la renvoie.
Guffa
2
MDN suggère d'utiliser String.prototype.substringplus String.prototype.substr.
Mikemike
33

Il y a beaucoup de réponses ici, et toutes sont basées sur deux méthodes:

  • METHODE 1: diviser la chaîne en utilisant deux sous-chaînes et remplir le caractère entre elles
  • MÉTHODE2: convertir la chaîne en tableau de caractères, remplacer un membre du tableau et le rejoindre

Personnellement, j'utiliserais ces deux méthodes dans des cas différents. Laisse-moi expliquer.

@FabioPhms: Votre méthode était celle que j'ai utilisée initialement et j'avais peur qu'elle soit mauvaise sur une chaîne avec beaucoup de caractères. Cependant, la question est de savoir quel est le nombre de personnages? Je l'ai testé sur 10 paragraphes "lorem ipsum" et cela m'a pris quelques millisecondes. Ensuite, je l'ai testé sur une corde 10 fois plus grande - il n'y avait vraiment pas de grande différence. Hm.

@vsync, @Cory Mawhorter: Vos commentaires sont sans ambiguïté; cependant, encore une fois, qu'est-ce qu'une grosse chaîne? Je suis d'accord que pour 32 ... 100kb les performances devraient être meilleures et que l'on devrait utiliser la sous-chaîne-variante pour cette opération de remplacement de caractère.

Mais qu'arrivera-t-il si je dois faire pas mal de remplacements?

Je devais effectuer mes propres tests pour prouver ce qui est plus rapide dans ce cas. Disons que nous avons un algorithme qui manipulera une chaîne relativement courte composée de 1000 caractères. Nous nous attendons à ce qu'en moyenne chaque caractère de cette chaîne soit remplacé ~ 100 fois. Ainsi, le code pour tester quelque chose comme ceci est:

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

J'ai créé un violon pour ça, et c'est ici . Il existe deux tests, TEST1 (sous-chaîne) et TEST2 (conversion de tableau).

Résultats:

  • TEST1: 195ms
  • TEST2: 6 ms

Il semble que la conversion de tableau bat la sous-chaîne de 2 ordres de grandeur! Alors - qu'est-ce qui s'est passé ici ???

Ce qui se passe réellement, c'est que toutes les opérations dans TEST2 sont effectuées sur le tableau lui-même, en utilisant l'expression d'affectation comme strarr2[p] = n. L'affectation est vraiment rapide par rapport à une sous-chaîne sur une grande chaîne, et il est clair que cela va gagner.

Il s'agit donc de choisir le bon outil pour le travail. Encore.

OzrenTkalcecKrznaric
la source
7
Déplacement de votre test vers jsperf, avec des résultats très différents: jsperf.com/string-replace-character . Il s'agit de choisir le bon outil pour le travail;)
colllin
1
@colllin: Je suis absolument d'accord. J'ai donc presque littéralement cloné les tests de jsfiddle vers jsperf. Cependant, en plus d'utiliser le bon outil, vous devez le faire de la bonne manière. Faites attention au problème, nous parlons de ce qui se passera si nous devons faire quelques remplacements dans un algorithme. L'exemple concret comprend 10000 remplacements. Cela signifie qu'un test doit inclure 10000 remplacements. Donc, en utilisant jsperf, j'ai obtenu des résultats assez cohérents, voir: jsperf.com/… .
OzrenTkalcecKrznaric
1
c'est pourquoi je n'aime pas javascript. de tels cas d'utilisation fréquents, intuitifs et évidents ne sont pas prévus. Vous penseriez qu'il arriverait aux rédacteurs de javascript que les gens pourraient vouloir remplacer les caractères dans les chaînes et qu'ils décideraient de mettre des méthodes pratiques dans la langue.
ahnbizcad
1
@colllin a fait quelque chose de différent de OzrenTkalcecKrznaric. OzrenTkalcecKrznaric a fait l'hypothèse que la chaîne est statique et que le fractionnement peut être optimisé avant les exécutions. Ce qui n'est pas forcément vrai. si vous devez vous séparer à chaque exécution, l'approche de la sous-chaîne est environ deux fois quatre fois plus rapide sur les petites chaînes, et plus rapide est la taille de la chaîne. À mon avis, cela fait de la sous-chaîne la meilleure implémentation pour la plupart des cas d'utilisation, sauf un grand nombre de modifications sur une grande chaîne statique.
WiR3D
3
Le problème est que lors du test 2, le fractionnement et la jointure sont en dehors de la boucle for, où vous comparez le remplacement d'un caractère par un multiple (injuste), la première méthode est plus rapide pour les remplacements simples et la seconde est meilleure pour les remplacements chaînés les uns après les autres.
Θεόφιλος Μουρατίδης
32

Le travail avec des vecteurs est généralement plus efficace pour contacter String.

Je suggère la fonction suivante:

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

Exécutez cet extrait:

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
la source
9
c'est mauvais pour les grandes chaînes, pas besoin de créer un tableau avec une quantité folle de cellules si vous pouvez simplement utiliser substr pour le couper ...
vsync
1
Utile si vous devez changer beaucoup de caractères, et c'est simple.
Sheepy
6
J'ai créé un test sur jsperf: jsperf.com/replace-character-by-index - Substr est beaucoup plus rapide et cohérent de 32 octets à 100 Ko. J'ai voté pour cela et autant que cela me fait mal de dire, même si cela semble plus agréable, substr est le meilleur choix pour les cordes de toute taille.
Cory Mawhorter
Ce n'est pas optimal.
Radko Dinev
C'est une bonne solution rapide si vous savez que vous allez utiliser de petites chaînes. Si vous êtes d'accord pour étendre les prototypes, vous pouvez obtenir un comportement similaire en 2 lignes:Array.prototype.replace = function(index, val) { this[index] = val; return this; }; 'word'.split('').replace(1, '0').join(''); // returns 'w0rd'
Michael Plautz
29

En Javascript, les chaînes sont immuables, vous devez donc faire quelque chose comme

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

Pour remplacer le caractère de x en i par «h»

DevDevDev
la source
28
str = str.split('');
str[3] = 'h';
str = str.join('');
colllin
la source
4
Clair et simple, mais ne fonctionnera pas actuellement avec les emoji (tels que 😀) lors de l'utilisation de splitetjoin
Vert
1
Avec es6, je pense que Array.from (str) pourrait être une meilleure option maintenant, mais je suis venu ici avec cette connaissance et j'ai appris quelque chose de tout aussi concis, alors merci!
David Kamer
7

One-liner utilisant String.replace avec callback (pas de support emoji):

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

Expliqué:

//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
la source
6

Cette méthode est bonne pour les chaînes de petite longueur mais peut être lente pour un texte plus volumineux.

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
la source
3

@CemKalyoncu: Merci pour la bonne réponse!

Je l'ai également légèrement adapté pour le rendre plus proche de la méthode Array.splice (et pris en compte la note 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
la source
Je ne sais pas pourquoi cela a été rejeté. C'est une réponse légitime. Cela fonctionne comme indiqué. Et c'est cohérent avec la Array.splicefonctionnalité de type.
Scrimothy
3

Cela fonctionne de manière similaire à Array.splice:

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

Tu pourrais essayer

var strArr = str.split("");

strArr[0] = 'h';

str = strArr.join("");
Mehulkumar
la source
2

Si vous souhaitez remplacer des caractères dans une chaîne, vous devez créer des chaînes modifiables. Ce sont essentiellement des tableaux de caractères. Vous pouvez créer une usine:

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

Ensuite, vous pouvez accéder aux caractères et l'ensemble du tableau convertit en chaîne lorsqu'il est utilisé comme chaîne:

  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ň
la source
2

En généralisant la réponse d'Afanasii Kurakin, nous avons:

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

Développons et expliquons à la fois l'expression régulière et la fonction de remplacement:

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

L'expression régulière .correspond exactement à un caractère. Le gfait correspondre à tous les caractères d'une boucle for. La replacerfonction est appelée en fonction du caractère d'origine et de l'index de l'emplacement de ce caractère dans la chaîne. Nous faisons une simple ifdéclaration pour déterminer si nous allons retourner soit origCharou newChar.

Stephen Quan
la source
2

Vous pouvez étendre le type de chaîne pour inclure la méthode incrustée:

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

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

Ensuite, vous pouvez appeler la fonction:

mbadeveloper
la source
1

J'ai fait une fonction qui fait quelque chose de similaire à ce que vous demandez, il vérifie si un caractère dans une chaîne est dans un tableau de caractères non autorisés s'il le remplace par ''

    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
la source
1

cela est facilement réalisable avec 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
la source
1

Voici une version que j'ai trouvée si vous souhaitez styliser des mots ou des caractères individuels à leur index dans react / javascript.

replaceAt( yourArrayOfIndexes, yourString/orArrayOfStrings ) 

Exemple de travail: https://codesandbox.io/s/ov7zxp9mjq

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

Et voici une autre méthode alternative

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

Et un autre...

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
la source
0

Je sais que c'est ancien mais la solution ne fonctionne pas pour un indice négatif, j'y ajoute donc un patch. j'espère que ça aide quelqu'un

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
la source
0

Disons que vous souhaitez remplacer l' Kthindex (index basé sur 0) par 'Z'. Vous pouvez utiliser Regexpour ce faire.

var re = var re = new RegExp("((.){" + K + "})((.){1})")
str.replace(re, "$1A$`");
ksp
la source
Une idée pourquoi ce tag n'est-il pas utile?
ksp
Je n'ai pas vérifié si cette expression régulière fonctionne, mais elle est peut-être rétrogradée car il est probablement beaucoup plus rapide de créer une nouvelle chaîne que de compiler une machine à états (expression régulière), ce qui est très cher.
Felo Vilches le
0

Vous pouvez utiliser la fonction suivante pour remplacer Characterou Stringà une position particulière d'une chaîne. Pour remplacer tous les cas de correspondance suivants, utilisez la String.prototype.replaceAllMatches()fonction.

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

Tester:

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

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

Production:

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

Voici ma solution en utilisant l'opérateur ternaire et cartographique. Fin plus lisible et maintenable plus facile à comprendre si vous me le demandez.

C'est plus dans es6 et les meilleures pratiques.

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
la source
-3

Les méthodes ici sont compliquées. Je le ferais de cette façon:

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

C'est aussi simple que possible.

mikey
la source
6
Pas maintenant. En fait, il remplacera la première occurrence du caractère. Toujours incorrecte.
Tomáš Zato - Rétablir Monica le