Wie ersetze ich ein Zeichen an einem bestimmten Index in JavaScript?

544

Angenommen, ich habe eine Zeichenfolge Hello worldund muss das Zeichen bei Index 3 ersetzen. Wie kann ich ein Zeichen durch Angabe eines Index ersetzen?

var str = "hello world";

Ich brauche so etwas

str.replaceAt(0,"h");
Santhosh
quelle
131
Was seltsam ist, ist, dass str[0] = 'x'es keine Fehler zu werfen scheint, aber nicht den gewünschten Effekt hat!
Michael
6
@Michael damit würden Sie den Index auf 0 bekommen, setzen Sie ihn auf 'x', diese Anweisung an sich würde den neuen Wert zurückgeben; 'x'. Aber all dies ändert nichts am Original, so dass es vollkommen gültig ist, nur nicht das, was Sie erwartet haben. Es ist keine Referenz
Paul Scheltema
8
@ Michael tut es, wenn "use strict"aktiviert ist: Uncaught TypeError: Cannot assign to read only property '0' of string 'hello world'(zumindest in Webkit-Browsern)
Jan Turoň
1
Javascript-Zeichenfolgen sind unveränderlich. Sie können nicht "an Ort und Stelle" geändert werden, sodass Sie kein einzelnes Zeichen ändern können. Tatsächlich ist jedes Vorkommen derselben Zeichenfolge EIN Objekt.
Martijn Scheffer
ok, siehe die Antwort: D
Martijn Scheffer

Antworten:

611

In JavaScript sind Zeichenfolgen unveränderlich . Das Beste, was Sie tun können, ist, eine neue Zeichenfolge mit dem geänderten Inhalt zu erstellen und die Variable zuzuweisen, die darauf verweist.

Sie müssen die replaceAt()Funktion selbst definieren :

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

Und benutze es so:

var hello = "Hello World";
alert(hello.replaceAt(2, "!!")); // Should display He!!o World
Cem Kalyoncu
quelle
101
Beachten Sie, dass es im Allgemeinen keine gute Idee ist, Basis-JavaScript-Klassen zu erweitern. Verwenden Sie stattdessen eine einfache Dienstprogrammfunktion.
Ates Goral
86
Ich muss fragen warum? Zu diesem Zweck gibt es Prototypenunterstützung.
Cem Kalyoncu
30
@CemKalyoncu: Es kann dazu führen, dass Code mit anderen Bibliotheken schlecht abgespielt wird . Aber ich bin selbst noch nie davon gebissen worden.
Alex
6
@alex: Da hast du recht, du musst wirklich prüfen, ob diese Funktion existiert, bevor du sie machst. Aber selbst wenn dies der Fall ist, sollte es genau den gleichen Vorgang ausführen.
Cem Kalyoncu
80
Ich bin anderer Meinung, auch wenn Sie feststellen, ob die Funktion vorhanden ist, kann eine spätere Bibliothek eine ähnliche Funktion verwenden / erstellen - 2 schlechte Ideen machen eine schlechtere. Spielen Sie im Allgemeinen niemals mit dem Code anderer Leute herum (einschließlich des Kernsystems). Erstellen Sie eine neue Funktion.
Martyman
93

replaceAtIn JavaScript gibt es keine Funktion. Mit dem folgenden Code können Sie jedes Zeichen in einer beliebigen Zeichenfolge an der angegebenen Position ersetzen:

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
quelle
Ich bevorzuge diese Lösung, weil Sie ein einzelnes Zeichen durch dieses ersetzen können. Die Lösung mit den meisten Upvotes funktioniert nicht, wenn Sie nur ein Zeichen ersetzen möchten. Es funktioniert nur, wenn zwei Zeichen ersetzt werden! Außerdem sollte substr durch substring ersetzt werden, wie in vielen anderen Kommentaren erwähnt.
Gignu
74

Das kannst du nicht. Nehmen Sie die Zeichen vor und nach der Position und setzen Sie sie in eine neue Zeichenfolge:

var s = "Hello world";
var index = 3;
s = s.substring(0, index) + 'x' + s.substring(index + 1);
Guffa
quelle
Eigentlich ja, das kannst du, aber es wäre ein Overkill. Sie können einen regulären Ausdruck einrichten, um den ersten Index - 1 Zeichen - zu überspringen und mit dem Zeichen am Index übereinzustimmen. Sie können String.replace mit diesem regulären Ausdruck verwenden, um eine direkte direkte Ersetzung durchzuführen. Aber es ist ein Overkill. In der Praxis kann man das also nicht. Aber theoretisch können Sie.
Ates Goral
12
@Ates: Die Ersetzungsfunktion führt keine direkte Ersetzung durch, sondern erstellt eine neue Zeichenfolge und gibt sie zurück.
Guffa
2
MDN schlägt vor, String.prototype.substringüber zu verwenden String.prototype.substr.
Mikemike
33

Hier gibt es viele Antworten, und alle basieren auf zwei Methoden:

  • METHODE 1: Teilen Sie die Zeichenfolge mit zwei Teilzeichenfolgen und füllen Sie das Zeichen dazwischen
  • METHODE 2: Konvertieren Sie die Zeichenfolge in ein Zeichenarray, ersetzen Sie ein Arraymitglied und verbinden Sie es

Persönlich würde ich diese beiden Methoden in verschiedenen Fällen anwenden. Lassen Sie mich erklären.

@FabioPhms: Ihre Methode war die, die ich ursprünglich verwendet habe, und ich hatte Angst, dass sie auf einer Zeichenfolge mit vielen Zeichen schlecht ist. Die Frage ist jedoch, was viele Charaktere sind. Ich habe es an 10 "Lorem Ipsum" -Absätzen getestet und es hat ein paar Millisekunden gedauert. Dann habe ich es an einer 10-mal größeren Saite getestet - es gab wirklich keinen großen Unterschied. Hm.

@vsync, @Cory Mawhorter: Ihre Kommentare sind eindeutig; Was ist jedoch wieder eine große Zeichenfolge? Ich bin damit einverstanden, dass für 32 ... 100kb die Leistung besser sein sollte und man für diese eine Operation der Zeichenersetzung eine Teilzeichenfolgenvariante verwenden sollte.

Aber was passiert, wenn ich einige Ersetzungen vornehmen muss?

Ich musste meine eigenen Tests durchführen, um zu beweisen, was in diesem Fall schneller ist. Angenommen, wir haben einen Algorithmus, der eine relativ kurze Zeichenfolge manipuliert, die aus 1000 Zeichen besteht. Wir erwarten, dass im Durchschnitt jedes Zeichen in dieser Zeichenfolge ~ 100 Mal ersetzt wird. Der Code zum Testen von so etwas lautet also:

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

Ich habe eine Geige dafür geschaffen, und sie ist hier . Es gibt zwei Tests, TEST1 (Teilzeichenfolge) und TEST2 (Array-Konvertierung).

Ergebnisse:

  • TEST1: 195 ms
  • TEST2: 6 ms

Es scheint, dass die Array-Konvertierung die Teilzeichenfolge um 2 Größenordnungen übertrifft! Also - was zur Hölle ist hier passiert ???

Was tatsächlich passiert, ist, dass alle Operationen in TEST2 auf dem Array selbst ausgeführt werden, wobei Zuweisungsausdrücke wie verwendet werden strarr2[p] = n. Die Zuweisung ist im Vergleich zur Teilzeichenfolge auf einer großen Zeichenfolge sehr schnell und es ist klar, dass sie gewinnen wird.

Es geht also darum, das richtige Werkzeug für den Job auszuwählen. Nochmal.

OzrenTkalcecKrznaric
quelle
7
Sie haben Ihren Test nach jsperf verschoben, mit sehr unterschiedlichen Ergebnissen: jsperf.com/string-replace-character . Es geht darum, das richtige Werkzeug für den Job
auszuwählen
1
@colllin: Ich stimme absolut zu. Also habe ich die Tests fast buchstäblich von jsfiddle auf jsperf geklont. Abgesehen von der Verwendung des richtigen Werkzeugs müssen Sie dies jedoch auf die richtige Weise tun. Achten Sie auf das Problem, wir sprechen darüber, was passieren wird, wenn wir einige Ersetzungen in einem Algorithmus vornehmen müssen. Das konkrete Beispiel enthält 10000 Ersetzungen. Dies bedeutet, dass ein Test 10000 Ersetzungen umfassen sollte. Mit jsperf habe ich also ziemlich konsistente Ergebnisse erzielt, siehe: jsperf.com/… .
OzrenTkalcecKrznaric
1
Deshalb mag ich kein Javascript. Solche häufigen, intuitiven und offensichtlichen Anwendungsfälle sind nicht vorgesehen. Sie würden denken, es würde den Autoren von Javascript in den Sinn kommen, dass die Leute Zeichen innerhalb von Zeichenfolgen ersetzen möchten und dass sie sich dafür entscheiden würden, bequeme Methoden in die Sprache einzufügen.
Ahnbizcad
1
@colllin hat etwas anderes gemacht als OzrenTkalcecKrznaric. OzrenTkalcecKrznaric ging davon aus, dass der String statisch ist und der Split vor den Läufen optimiert werden kann. Welches ist nicht unbedingt wahr. Wenn Sie bei jedem Lauf teilen müssen, ist der Teilstring-Ansatz bei kleinen Zeichenfolgen etwa zweimal viermal schneller und nur umso schneller, je größer die Zeichenfolge wird. Meiner Meinung nach ist der Teilstring die bessere Implementierung für die meisten Anwendungsfälle, abgesehen von einer großen Anzahl von Änderungen an einer großen statischen Zeichenfolge.
WiR3D
3
Das Problem ist, dass bei Test2 Split und Join außerhalb der for-Schleife liegen, in der Sie das Ersetzen einzelner Zeichen mit einem Ersetzen mit mehreren Zeichen vergleichen (unfair). Die erste Methode ist schneller für einzelne Ersetzungen und die zweite Methode besser für verkettete Ersetzungen nacheinander
Θεόφιλος Μουρατίδης
32

Die Arbeit mit Vektoren ist normalerweise am effektivsten, um String zu kontaktieren.

Ich schlage folgende Funktion vor:

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

Führen Sie dieses Snippet aus:

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
quelle
9
Dies ist schlecht für große Zeichenfolgen. Sie müssen kein Array mit einer verrückten Anzahl von Zellen erstellen, wenn Sie nur substr verwenden können, um es zu schneiden ...
vsync
1
Nützlich, wenn Sie viele Zeichen ändern müssen, und es ist einfach.
Sheepy
6
Ich habe einen Test für jsperf erstellt: jsperf.com/replace-character-by-index - Substr ist viel schneller und konsistent von 32 Byte bis zu 100 KB. Ich habe dies positiv bewertet und so sehr es mich auch schmerzt zu sagen, obwohl sich das besser anfühlt, ist substr die bessere Wahl für Saiten jeder Größe.
Cory Mawhorter
Das ist ziemlich unoptimal.
Radko Dinev
Dies ist eine gute schnelle Lösung, wenn Sie wissen, dass Sie kleine Zeichenfolgen verwenden werden. Wenn Sie mit der Erweiterung der Prototypen einverstanden sind, können Sie ein ähnliches Verhalten in zwei Zeilen erzielen:Array.prototype.replace = function(index, val) { this[index] = val; return this; }; 'word'.split('').replace(1, '0').join(''); // returns 'w0rd'
Michael Plautz
29

In Javascript sind Zeichenfolgen unveränderlich, so dass Sie so etwas tun müssen

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

So ersetzen Sie das Zeichen in x bei i durch 'h'

DevDevDev
quelle
28
str = str.split('');
str[3] = 'h';
str = str.join('');
Colllin
quelle
4
Klar und einfach, funktioniert aber derzeit nicht mit Emoji (wie 😀), wenn splitundjoin
Green
1
Mit es6 denke ich, dass Array.from (str) jetzt eine bessere Option sein könnte, aber ich bin mit diesem Wissen hierher gekommen und habe etwas genauso Prägnantes von Ihnen gelernt, also danke!
David Kamer
7

Einzeiler mit String.replace mit Rückruf (keine Emoji-Unterstützung):

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

Erklärt:

//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
quelle
6

Diese Methode eignet sich für Zeichenfolgen mit kleiner Länge, kann jedoch für größeren Text langsam sein.

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

@CemKalyoncu: Danke für die tolle Antwort!

Ich habe es auch leicht angepasst, um es der Array.splice-Methode ähnlicher zu machen (und die Anmerkung von @Ates berücksichtigt):

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
quelle
Ich bin mir nicht sicher, warum dies abgelehnt wurde. Es ist eine legitime Antwort. Es funktioniert wie angegeben. Und es stimmt mit der Array.spliceTypfunktionalität überein .
Scrimothy
3

Dies funktioniert ähnlich wie Array.splice:

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

Du könntest es versuchen

var strArr = str.split("");

strArr[0] = 'h';

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

Wenn Sie Zeichen in Zeichenfolgen ersetzen möchten, sollten Sie veränderbare Zeichenfolgen erstellen. Dies sind im Wesentlichen Zeichenarrays. Sie könnten eine Fabrik erstellen:

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

Dann können Sie auf die Zeichen zugreifen und das gesamte Array wird in eine Zeichenfolge konvertiert, wenn es als Zeichenfolge verwendet wird:

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

Wenn wir die Antwort von Afanasii Kurakin verallgemeinern, haben wir:

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

Lassen Sie uns sowohl den regulären Ausdruck als auch die Ersetzungsfunktion erweitern und erklären:

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

Der reguläre Ausdruck .entspricht genau einem Zeichen. Damit gpasst es zu jedem Zeichen in einer for-Schleife. Die replacerFunktion wird sowohl mit dem Originalzeichen als auch mit dem Index aufgerufen, in dem sich das Zeichen in der Zeichenfolge befindet. Wir geben eine einfache ifErklärung ab, um festzustellen, ob wir entweder origCharoder zurückkehren werden newChar.

Stephen Quan
quelle
2

Sie können den Zeichenfolgentyp um die Inset-Methode erweitern:

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

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

Dann können Sie die Funktion aufrufen:

Entwickler
quelle
1

Ich habe eine Funktion ausgeführt, die etwas Ähnliches wie das tut, was Sie fragen. Sie prüft, ob sich ein Zeichen in einer Zeichenfolge in einem Array nicht zulässiger Zeichen befindet, wenn es durch '' ersetzt wird.

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

Dies ist mit RegExp leicht zu erreichen!

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

Hier ist eine Version, die ich mir ausgedacht habe, wenn Sie Wörter oder einzelne Zeichen an ihrem Index in React / Javascript formatieren möchten.

replaceAt( yourArrayOfIndexes, yourString/orArrayOfStrings ) 

Arbeitsbeispiel: https://codesandbox.io/s/ov7zxp9mjq

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

Und hier ist eine andere alternative Methode

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

Und ein anderer...

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

Ich weiß, dass dies alt ist, aber die Lösung funktioniert nicht für negative Indizes, daher füge ich einen Patch hinzu. hoffe es hilft jemandem

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

Nehmen wir an, Sie möchten den KthIndex (0-basierten Index) durch ersetzen 'Z'. Sie könnten Regexdies verwenden.

var re = var re = new RegExp("((.){" + K + "})((.){1})")
str.replace(re, "$1A$`");
ksp
quelle
Irgendeine Idee, warum dieses Tag nicht nützlich ist?
ksp
Ich habe nicht überprüft, ob dieser reguläre Ausdruck funktioniert, aber vielleicht wurde er herabgestuft, weil das Erstellen einer neuen Zeichenfolge wahrscheinlich viel schneller ist als das Kompilieren einer Zustandsmaschine (regulärer Ausdruck), was sehr teuer ist.
Felo Vilches
0

Sie können die folgende Funktion verwenden, um einen String zu ersetzen Characteroder Stringan einer bestimmten Position. Verwenden Sie die String.prototype.replaceAllMatches()Funktion, um alle folgenden Übereinstimmungsfälle zu ersetzen .

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

Prüfung:

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

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

Ausgabe:

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

Hier ist meine Lösung mit dem ternären und Kartenoperator. Besser lesbares, wartbares Ende leichter zu verstehen, wenn Sie mich fragen.

Es geht mehr um es6 und Best Practices.

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

Die Methoden hier sind kompliziert. Ich würde es so machen:

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

Das ist so einfach wie es nur geht.

mikey
quelle
6
Nicht wirklich. Tatsächlich ersetzt es das erste Auftreten des Zeichens. Immer noch falsch.
Tomáš Zato - Wiedereinsetzung Monica