JavaScript'te belirli bir dizindeki bir karakteri nasıl değiştiririm?


544

Bir dize var diyelim Hello worldve indeks 3 char değiştirmek gerekir. Nasıl bir indeks belirterek char değiştirebilirsiniz?

var str = "hello world";

Gibi bir şeye ihtiyacım var

str.replaceAt(0,"h");

131
Garip olan şey str[0] = 'x', herhangi bir hata atmıyor gibi görünüyor, ancak istenen etkiye sahip değil!
Michael

6
@Michael, indeksi 0'da alıp 'x' olarak ayarlayacağınızı, bu ifadenin kendisi yeni değeri döndüreceğini; 'x'. ama hepsi orijinali değiştirmez, bu yüzden tamamen geçerli, beklediğiniz gibi değil. bir referans değil
Paul Scheltema

8
@Michael "use strict"etkinleştirilirse yapar: Uncaught TypeError: Cannot assign to read only property '0' of string 'hello world'(en azından webkit tarayıcılarında)
Jan Turoň

1
Javascript dizeleri değiştirilemez, "yerinde" değiştirilemezler, böylece tek bir karakteri değiştiremezsiniz. aslında aynı dizgenin her oluşumu BİR nesnedir.
Martijn Scheffer

tamam, cevaba bakınız: D
Martijn Scheffer

Yanıtlar:


611

JavaScript'te, dizeler değiştirilemez , yani yapabileceğiniz en iyi şey, değiştirilen içerikle yeni bir dize oluşturmak ve değişkeni işaret edecek şekilde atamaktır.

replaceAt()İşlevi kendiniz tanımlamanız gerekir :

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

Ve şu şekilde kullanın:

var hello = "Hello World";
alert(hello.replaceAt(2, "!!")); // Should display He!!o World

101
Temel JavaScript sınıflarını genişletmenin genellikle iyi bir fikir olmadığını unutmayın. Bunun yerine düz bir yardımcı program işlevi kullanın.
Ateş Goral

86
Neden diye sormalıyım? Prototip desteği bu amaç için var.
Cem Kalyoncu

30
@CemKalyoncu: Kodun diğer kütüphanelerle kötü oynatılmasını sağlayabilir . Ama ben bundan hiç ısırılmadım.
alex

6
@alex: bu konuda haklısın, gerçekten bu işlevin yapmadan önce var olup olmadığını kontrol etmelisin. Ama yine de öyle olsa bile, aynı işlemi yapmalıdır.
Cem Kalyoncu

80
Ben katılmıyorum, eğer fonksiyonun var olup olmadığını tespit etseniz bile, daha sonraki bir kütüphane hala benzer bir fonksiyonu kullanabilir / yaratabilir - 2 kötü fikir daha kötü bir şey yapar. Genel olarak, asla diğer insanların kodlarıyla oynamayın (çekirdek sistemi dahil edin). Yeni bir işlev oluşturun.
martyman

93

replaceAtJavaScript'te işlev yok . Belirtilen konumdaki herhangi bir dizgideki herhangi bir karakteri değiştirmek için aşağıdaki kodu kullanabilirsiniz:

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>



Bu çözümü tercih ediyorum çünkü tek bir karakteri onunla değiştirebilirsiniz. Yalnızca bir karakteri değiştirmek istiyorsanız en çok oy alan çözüm çalışmaz. Sadece iki karakteri değiştirirken çalışır! Ayrıca, substr diğer birçok yorumda belirtildiği gibi alt dize ile değiştirilmelidir.
gignu

74

Yapamazsın. Karakterleri konumdan önce ve sonra alın ve yeni bir dizeye yapıştırın:

var s = "Hello world";
var index = 3;
s = s.substring(0, index) + 'x' + s.substring(index + 1);

Aslında, evet, yapabilirsin, ama aşırıya kaçmak olurdu. İlk dizini atlamak için normal bir ifade ayarlayabilirsiniz - 1 karakter ve dizindeki karakterle eşleşir. Doğrudan, yerinde değiştirme yapmak için String.replace öğesini bu normal ifadeyle kullanabilirsiniz. Ama bu aşırı bir ölüm. Yani, pratikte yapamazsınız. Ama teoride yapabilirsiniz.
Ateş Goral

12
@Ates: replace işlevi yerinde değiştirme yapmaz, yeni bir dize oluşturur ve döndürür.
Guffa

2
MDN kullanmayı önerir String.prototype.substringüzerinde String.prototype.substr.
Mikemike

33

Burada birçok cevap var ve hepsi iki yönteme dayanıyor:

  • YÖNTEM1: dizeyi iki alt dize kullanarak böl ve aradaki karakteri doldur
  • YÖNTEM2: dizeyi karakter dizisine dönüştür, bir dizi üyesini değiştir ve ona katıl

Şahsen, bu iki yöntemi farklı durumlarda kullanırdım. Açıklamama izin ver.

@FabioPhms: Metodunuz başlangıçta kullandığım yöntemdi ve çok sayıda karakter içeren dizede kötü olduğundan korkuyordum. Ancak, soru çok karakter nedir? Ben 10 "lorem ipsum" paragraflarda test ve birkaç milisaniye sürdü. Sonra 10 kat daha büyük bir dizede test ettim - gerçekten büyük bir fark yoktu. Hm.

@vsync, @Cory Mawhorter: Yorumlarınız açık; Ancak, yine, büyük bir dize nedir? 32 ... 100kb performans için daha iyi olmalı ve karakter değiştirme işleminin bu alt dizisi için bir alt dize varyantı kullanması gerektiğini kabul ediyorum.

Ama birkaç değişiklik yapmam gerekirse ne olacak?

Bu durumda neyin daha hızlı olduğunu kanıtlamak için kendi testlerimi yapmam gerekiyordu. Diyelim ki 1000 karakterden oluşan nispeten kısa bir dizeyi işleyecek bir algoritmamız var. Ortalama olarak bu dizgideki her karakterin ~ 100 kez değiştirilmesini bekliyoruz. Yani, böyle bir şeyi test etmek için kod:

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

Bunun için bir keman yarattım ve burada . İki test vardır: TEST1 (alt dize) ve TEST2 (dizi dönüşümü).

Sonuçlar:

  • TEST1: 195 ms
  • TEST2: 6 ms

Dizi dönüşüm alt dizeyi 2 büyüklükte yener gibi görünüyor! Peki - burada ne oldu ???

Gerçekte olan, TEST2'deki tüm işlemlerin, atama ifadesi gibi dizinin kendisinde yapılmasıdır strarr2[p] = n. Atama, büyük bir dizgideki alt dizeye kıyasla gerçekten hızlıdır ve kazanacağı açıktır.

Yani, iş için doğru aracı seçmekle ilgili. Tekrar.


7
Testinizi çok farklı sonuçlarla jsperf'e taşıdı : jsperf.com/string-replace-character . Her şey iş için doğru aracı seçmekle ilgili;)
Colllin

1
@colllin: Kesinlikle katılıyorum. Bu yüzden neredeyse kelimenin tam anlamıyla jsfiddle'dan jsperf'e testleri klonladım. Bununla birlikte, doğru aracı kullanmanın yanı sıra, doğru şekilde yapmanız gerekir. Soruna dikkat edin, bir algoritmada birkaç değişiklik yapmak zorunda kalırsak neler olacağından bahsediyoruz. Somut örnek 10000 değişiklik içerir. Bu, bir testte 10000 değiştirme yapılması gerektiği anlamına gelir . Yani, jsperf kullanarak, oldukça tutarlı sonuçlar aldım, bkz: jsperf.com/… .
OzrenTkalcecKrznaric

1
bu yüzden javascript sevmiyorum. bu sık, sezgisel, açık kullanım durumları öngörülmemiştir. Javascript yazarlarına, insanların dizeler içindeki karakterleri değiştirmek isteyebileceklerini ve dile kolaylık yöntemlerini koymaya karar vereceğini düşünürdünüz.
ahnbizcad

1
@colllin, OzrenTkalcecKrznaric'ten farklı bir şey yaptı. OzrenTkalcecKrznaric, ipin statik olduğunu ve ayrılmanın çalışmalardan önce optimize edilebileceğini varsaydı. Bu mutlaka doğru değildir. her çalıştırmada bölmeniz gerekiyorsa, alt dize yaklaşımı küçük dizelerde yaklaşık iki kat 4 kat daha hızlıdır ve yalnızca daha hızlı dizge büyür. Bence bu, alt dizeyi çoğu kullanım durumunda daha iyi bir uygulama haline getirir ve büyük bir statik dize üzerinde çok sayıda değişiklik yapılmasını engeller.
WiR3D

3
Sorun, test2'de bölünmüş ve birleştirmenin for döngüsünün dışında olması, burada tek karakter değişimini birden fazla olanla (haksız) karşılaştırmanız, ilk yöntemin tekli değiştirmeler için daha hızlı olması ve ikincisinin zincirleme değiştirmeler için birbiri ardına daha iyi olmasıdır.
Θεόφιλος Μουρατίδης

32

Vektörlerle çalışmak genellikle String ile iletişim kurmak için en etkilidir.

Aşağıdaki işlevi öneririm:

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

Bu snippet'i çalıştırın:

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


9
Bu büyük dizeler için kötü, sadece kesmek için substr kullanabilirsiniz eğer deli miktarda hücre ile bir Array oluşturmaya gerek yok ...
vsync

1
Çok sayıda karakteri değiştirmeniz gerekiyorsa yararlıdır ve basittir.
Sheepy

6
Ben jsperf üzerinde bir test oluşturdum: jsperf.com/replace-character-by-index - Substr çok daha hızlı ve 32byte 100kb kadar tutarlı. Bunu destekledim ve söyleyebildiğim kadar acıyor, bu daha hoş hissetse bile, substr herhangi bir boyuttaki dizeler için daha iyi bir seçim.
Cory Mawhorter

Bu oldukça uygunsuz.
Radko Dinev

Küçük dizeler kullanacağınızı biliyorsanız, bu iyi ve hızlı bir çözümdür. Prototipleri genişletme konusunda sorun yaşıyorsanız, 2 satırda benzer davranışlar elde edebilirsiniz:Array.prototype.replace = function(index, val) { this[index] = val; return this; }; 'word'.split('').replace(1, '0').join(''); // returns 'w0rd'
Michael Plautz

29

Javascript dizeleri değişmez, bu yüzden böyle bir şey yapmak zorunda

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

İ'deki x'deki karakteri 'h' ile değiştirmek için


28
str = str.split('');
str[3] = 'h';
str = str.join('');

4
Açık ve basit, ancak şu anda emoji (😀 gibi) ile çalışmaz splitvejoin
Green

1
Es6 ile Array.from (str) 'un şimdi daha iyi bir seçenek olabileceğini düşünüyorum, ama buraya bu bilgiyle geldim ve sizden kısa ve öz bir şey öğrendim, teşekkürler!
David Kamer

7

Geri arama ile String.replace kullanan tek astar (emoji desteği yok):

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

Açıklaması:

//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
})

6

Bu yöntem, küçük uzunluklu dizeler için iyidir, ancak daha büyük metinler için yavaş olabilir.

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. 
*/

3

@CemKalyoncu: Harika cevap için teşekkürler!

Ayrıca, Array.splice yöntemi gibi daha fazla yapmak için biraz uyarladım (ve @Ates'in notunu dikkate aldım):

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!"

Bunun neden seçildiğinden emin değilim. Bu yasal bir cevap. Belirtildiği gibi çalışır. Ve Array.splicetür işlevselliği ile tutarlıdır .
Scrimothy

3

Bu şuna benzer Array.splice:

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

3

Deneyebilirsin

var strArr = str.split("");

strArr[0] = 'h';

str = strArr.join("");

2

Dizedeki karakterleri değiştirmek istiyorsanız, değiştirilebilir dizeler oluşturmanız gerekir. Bunlar aslında karakter dizileridir. Bir fabrika oluşturabilirsiniz:

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

Daha sonra karakterlere erişebilirsiniz ve dizenin tamamı dize olarak kullanıldığında dizeye dönüştürülür:

  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!"

2

Afanasii Kurakin'in cevabını genelleştirerek:

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

Hem normal ifadeyi hem de ikame işlevini genişletip açıklayalım:

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

Normal ifade .tam olarak bir karakterle eşleşir. gO döngü için her karakteri eşleştirmek yapar. Bu replacerişleve, hem orijinal karakter hem de bu karakterin dizede bulunduğu dizin verilir. ifYa origCharda geri dönüp dönmeyeceğimizi belirlemek için basit bir açıklama yaparız newChar.


2

Dize türünü inset yöntemini içerecek şekilde genişletebilirsiniz:

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

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

Sonra işlevi çağırabilirsiniz:


1

Sorduğunuza benzer bir şey yapan bir işlev yaptım, dizedeki bir karakterin izin verilmeyen karakterler dizisinde olup olmadığını kontrol eder ''

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

1

bu RegExp ile kolayca elde edilebilir!

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

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

//< "Hello RegExp"

1

Reac / javascript dizinindeki sözcükleri veya karakterleri tek tek dizmek istiyorsanız, burada bulduğum bir sürüm.

replaceAt( yourArrayOfIndexes, yourString/orArrayOfStrings ) 

Çalışma örneği: https://codesandbox.io/s/ov7zxp9mjq

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

Ve işte başka bir alternatif yöntem

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

Ve başka...

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

0

Bu eski olduğunu biliyorum ama çözüm negatif dizin için çalışmıyor, bu yüzden ona bir yama eklemek. umarım birine yardım eder

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

}

0

KthDizin (0 tabanlı dizin) ile değiştirmek istediğinizi varsayalım 'Z'. Bunu Regexyapmak için kullanabilirsiniz .

var re = var re = new RegExp("((.){" + K + "})((.){1})")
str.replace(re, "$1A$`");

Bu etiketlemenin neden yararlı olmadığı hakkında bir fikriniz var mı?
ksp

Bu normal ifadenin işe yarayıp yaramadığını kontrol etmedim, ancak belki de çok pahalı bir durum makinesini (normal ifade) derlemekten çok daha hızlı bir şekilde yeni bir dize oluşturmak için çok düşük.
Felo Vilches

0

Bir Dizeyi değiştirmek Characterveya Stringbelirli bir konumda aşağıdaki işlevi kullanabilirsiniz . Aşağıdaki tüm eşleşme durumlarını değiştirmek için String.prototype.replaceAllMatches()işlevini kullanı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;
};

Ölçek:

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

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

Çıktı:

Index Matched replace :  yash yas $dfd*.**
Index Matched replace :  yash ~as $dfdas.**

-1

İşte üçlü ve harita operatörünü kullanarak benim çözüm. Bana sorarsanız daha okunabilir, bakımı kolay anlaşılır son.

Daha çok es6 ve en iyi uygulamalar.

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()"/>


-3

Buradaki yöntemler karmaşıktır. Bunu şu şekilde yaparım:

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

Bu olabildiğince basit.


6
Aslında değil. Aslında, karakterin ilk oluşumunun yerini alacak. Hala yanlış.
Tomáš Zato - Monica
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.