Làm cách nào để thay thế một ký tự tại một chỉ mục cụ thể trong JavaScript?


544

Tôi có một chuỗi, giả sử Hello worldvà tôi cần thay thế char ở chỉ số 3. Làm cách nào tôi có thể thay thế một char bằng cách chỉ định một chỉ mục?

var str = "hello world";

Tôi cần một cái gì đó như

str.replaceAt(0,"h");

131
Điều kỳ lạ là str[0] = 'x'dường như không có bất kỳ lỗi nào, nhưng không có hiệu quả mong muốn!
Michael

6
@Michael với điều đó bạn sẽ nhận được chỉ số ở mức 0, đặt nó thành 'x', chính câu lệnh đó sẽ trả về giá trị mới; 'x'. nhưng tất cả đều không thay đổi nguồn gốc, vì vậy nó hoàn toàn hợp lệ, không như bạn mong đợi. nó không phải là một tài liệu tham khảo
Paul Scheltema

8
@Michael nó thực hiện nếu "use strict"được kích hoạt: Uncaught TypeError: Cannot assign to read only property '0' of string 'hello world'(ít nhất là trong các trình duyệt webkit)
Jan Turoň

1
Chuỗi Javascript là bất biến, chúng không thể được sửa đổi "tại chỗ" để bạn không thể sửa đổi một ký tự. trong thực tế, mọi sự xuất hiện của cùng một chuỗi là MỘT đối tượng.
Martijn Scheffer

ok, xem câu trả lời: D
Martijn Scheffer

Câu trả lời:


611

Trong JavaScript, các chuỗi là bất biến , điều đó có nghĩa là điều tốt nhất bạn có thể làm là tạo một chuỗi mới với nội dung đã thay đổi và gán biến để trỏ đến nó.

Bạn sẽ cần tự xác định replaceAt()chức năng:

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

Và sử dụng nó như thế này:

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

101
Lưu ý rằng nói chung không nên mở rộng các lớp JavaScript cơ bản. Sử dụng một chức năng tiện ích đơn giản thay thế.
Ates Goral

86
Tôi phải hỏi tại sao? Hỗ trợ nguyên mẫu là có cho mục đích này.
Cem Kalyoncu

30
@CemKalyoncu: Nó có thể khiến mã phát xấu với các thư viện khác. Nhưng bản thân tôi chưa bao giờ bị cắn bởi điều đó.
alex

6
@alex: bạn nói đúng về điều đó, bạn thực sự cần kiểm tra xem hàm đó có tồn tại hay không trước khi thực hiện. Nhưng ngay cả khi nó làm, nó sẽ thực hiện chính xác hoạt động tương tự.
Cem Kalyoncu

80
Tôi không đồng ý, ngay cả khi bạn phát hiện xem hàm có tồn tại thư viện sau này hay không vẫn có thể sử dụng / tạo một hàm tương tự - 2 ý tưởng tồi làm cho một ý tưởng tồi tệ hơn. Nói chung, không bao giờ chơi xung quanh với mã người khác (bao gồm hệ thống cốt lõi). Tạo một chức năng mới.
martyman

93

Không có replaceAtchức năng trong JavaScript. Bạn có thể sử dụng đoạn mã sau để thay thế bất kỳ ký tự nào trong bất kỳ chuỗi nào tại vị trí đã chỉ định:

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>



Tôi đặt trước giải pháp này vì bạn có thể thay thế một ký tự bằng nó. Giải pháp có nhiều upvote nhất không hoạt động nếu bạn chỉ muốn thay thế một ký tự. Nó chỉ hoạt động khi thay thế hai nhân vật! Ngoài ra, chất nền nên được thay thế bằng chuỗi con như được đề cập trong nhiều ý kiến ​​khác.
gignu

74

Bạn không thể. Lấy các ký tự trước và sau vị trí và nối vào một chuỗi mới:

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

Trên thực tế, có, bạn có thể, nhưng nó sẽ là một quá mức cần thiết. Bạn có thể thiết lập biểu thức chính quy để bỏ qua chỉ mục đầu tiên - 1 ký tự và khớp với ký tự đó trong chỉ mục. Bạn có thể sử dụng String.replace với biểu thức chính quy đó để thực hiện thay thế trực tiếp, tại chỗ. Nhưng đó là một quá mức cần thiết. Vì vậy, trong thực tế, bạn không thể. Nhưng trên lý thuyết, bạn có thể.
Ates Goral

12
@Ates: Hàm thay thế không thực hiện thay thế tại chỗ, nó tạo ra một chuỗi mới và trả về nó.
Guffa

2
MDN đề nghị sử dụng String.prototype.substringhơn String.prototype.substr.
Mikemike

33

Có rất nhiều câu trả lời ở đây, và tất cả chúng đều dựa trên hai phương pháp:

  • PHƯƠNG PHÁP1: phân tách chuỗi bằng hai chuỗi con và nhồi ký tự giữa chúng
  • METHOD2: chuyển đổi chuỗi thành mảng ký tự, thay thế một thành viên mảng và tham gia chuỗi đó

Cá nhân, tôi sẽ sử dụng hai phương pháp này trong các trường hợp khác nhau. Hãy để tôi giải thích.

@FabioPhms: Phương thức của bạn là phương pháp ban đầu tôi đã sử dụng và tôi sợ rằng nó không tốt trên chuỗi có nhiều ký tự. Tuy nhiên, câu hỏi là rất nhiều nhân vật? Tôi đã thử nghiệm nó trên 10 đoạn "lorem ipsum" và mất vài mili giây. Sau đó, tôi đã thử nghiệm nó trên chuỗi lớn hơn 10 lần - thực sự không có sự khác biệt lớn. Hừm.

@vsync, @Cory Mawhorter: Nhận xét của bạn không rõ ràng; tuy nhiên, một lần nữa, một chuỗi lớn là gì? Tôi đồng ý rằng với hiệu suất 32 ... 100kb nên tốt hơn và người ta nên sử dụng biến thể chuỗi con cho một thao tác thay thế ký tự này.

Nhưng điều gì sẽ xảy ra nếu tôi phải thực hiện một vài thay thế?

Tôi cần phải thực hiện các thử nghiệm của riêng mình để chứng minh cái gì nhanh hơn trong trường hợp đó. Giả sử chúng ta có một thuật toán sẽ thao tác một chuỗi tương đối ngắn bao gồm 1000 ký tự. Chúng tôi hy vọng rằng trung bình mỗi ký tự trong chuỗi đó sẽ được thay thế ~ 100 lần. Vì vậy, mã để kiểm tra một cái gì đó như thế này là:

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

Tôi đã tạo ra một câu đố cho điều này, và nó ở đây . Có hai bài kiểm tra, TEST1 (chuỗi con) và TEST2 (chuyển đổi mảng).

Các kết quả:

  • KIỂM TRA1: 195ms
  • KIỂM TRA2: 6ms

Có vẻ như chuyển đổi mảng đánh bại chuỗi con bằng 2 bậc độ lớn! Vậy - cái quái gì đã xảy ra ở đây ???

Điều thực sự xảy ra là tất cả các hoạt động trong TEST2 được thực hiện trên chính mảng, sử dụng biểu thức gán như thế nào strarr2[p] = n. Chuyển nhượng thực sự nhanh so với chuỗi con trên một chuỗi lớn và rõ ràng là nó sẽ thắng.

Vì vậy, tất cả là về việc chọn công cụ phù hợp cho công việc. Lần nữa.


7
Đã chuyển bài kiểm tra của bạn sang jsperf, với kết quả rất khác nhau: jsperf.com/opes-replace-character . Đó là tất cả về việc chọn công cụ phù hợp cho công việc;)
colllin

1
@colllin: Mình hoàn toàn đồng ý. Vì vậy, tôi gần như nhân bản các bài kiểm tra từ jsfiddle sang jsperf. Tuy nhiên, ngoài việc sử dụng đúng công cụ, bạn phải làm điều đó đúng cách. Hãy chú ý đến vấn đề, chúng ta đang nói về những gì sẽ xảy ra nếu chúng ta phải thực hiện một vài thay thế trong một thuật toán. Ví dụ cụ thể bao gồm 10000 thay thế. Điều này có nghĩa là một bài kiểm tra nên bao gồm 10000 thay thế. Vì vậy, bằng cách sử dụng jsperf, tôi đã nhận được kết quả khá nhất quán, xem: jsperf.com/ .
OzrenTkalcecKrznaric

1
đây là lý do tại sao tôi không thích javascript. trường hợp sử dụng thường xuyên, trực quan, rõ ràng như vậy không được cung cấp cho. Bạn nghĩ rằng điều đó sẽ xảy ra với những người viết javascript rằng mọi người có thể muốn thay thế các ký tự trong chuỗi và họ sẽ quyết định đưa các phương thức tiện lợi vào ngôn ngữ.
ahnbizcad

1
@colllin đã làm một cái gì đó khác với OzrenTkalcecKrznaric. OzrenTkalcecKrznaric đưa ra giả định rằng chuỗi là tĩnh và sự phân tách có thể được tối ưu hóa trước khi chạy. Điều này không nhất thiết là đúng. nếu bạn phải phân tách mỗi lần chạy thì cách tiếp cận chuỗi con nhanh hơn khoảng hai lần trên các chuỗi nhỏ và chỉ càng nhanh thì chuỗi càng lớn. Theo tôi, điều này làm cho chuỗi con thực hiện tốt hơn cho hầu hết các trường hợp sử dụng, chặn số lượng lớn các thay đổi trên một chuỗi tĩnh lớn.
WiR3D

3
Vấn đề là trên test2, phần tách và nối nằm ngoài vòng lặp for, trong đó bạn so sánh thay thế char đơn lẻ với nhiều cái (không công bằng), phương pháp đầu tiên nhanh hơn cho các thay thế đơn lẻ và phương pháp thứ hai tốt hơn cho các thay thế được nối tiếp nhau
Θεόφιλος Μουρατίδης

32

Làm việc với các vectơ thường hiệu quả nhất để liên hệ với String.

Tôi đề nghị các chức năng sau đây:

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

Chạy đoạn trích này:

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
điều này rất tệ cho các chuỗi lớn, không cần tạo một mảng với số lượng ô điên rồ nếu bạn chỉ có thể sử dụng chất nền để cắt nó ...
vsync

1
Hữu ích nếu bạn cần thay đổi nhiều ký tự, và nó rất đơn giản.
Cừu

6
Tôi đã tạo một thử nghiệm trên jsperf: jsperf.com/replace-character-by-index - Substr là cách nhanh hơn và nhất quán từ 32byte lên đến 100kb. Tôi đã ủng hộ điều này và nhiều như nó làm tôi đau lòng khi nói, mặc dù điều này cảm thấy đẹp hơn, chất nền là sự lựa chọn tốt hơn cho các chuỗi có kích thước bất kỳ.
Cory Mawhorter

Điều này là không tối ưu.
Radko Dinev

Đây là một giải pháp nhanh chóng tốt nếu bạn biết bạn sẽ sử dụng các chuỗi nhỏ. Nếu bạn ổn với việc mở rộng các nguyên mẫu, thì bạn có thể đạt được hành vi tương tự trong 2 dòng:Array.prototype.replace = function(index, val) { this[index] = val; return this; }; 'word'.split('').replace(1, '0').join(''); // returns 'w0rd'
Michael Plautz

29

Trong chuỗi Javascript là bất biến nên bạn phải làm một cái gì đó như

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

Để thay thế ký tự trong x tại i bằng 'h'


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

4
Rõ ràng và đơn giản, nhưng hiện tại sẽ không hoạt động với biểu tượng cảm xúc (chẳng hạn như) khi sử dụng splitjoin
Green

1
Với es6 tôi nghĩ rằng Array.from (str) có thể là một lựa chọn tốt hơn bây giờ, nhưng tôi đã đến đây với kiến ​​thức đó và học được điều gì đó ngắn gọn từ bạn nên cảm ơn bạn!
David Kamer

7

Một lớp lót sử dụng String.replace với gọi lại (không hỗ trợ biểu tượng cảm xúc):

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

Giải thích:

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

Phương pháp này tốt cho các chuỗi có độ dài nhỏ nhưng có thể chậm đối với văn bản lớn hơn.

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: Cảm ơn câu trả lời tuyệt vời!

Tôi cũng đã điều chỉnh nó một chút để làm cho nó giống với phương thức Array.splice hơn (và đã lưu ý đến ghi chú của @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!"

Không chắc chắn tại sao điều này đã được bỏ phiếu xuống. Đó là một câu trả lời hợp pháp. Nó hoạt động như chỉ định. Và nó phù hợp với Array.splicechức năng loại.
Scrimothy

3

Điều này hoạt động tương tự như Array.splice:

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

3

Bạn có thể thử

var strArr = str.split("");

strArr[0] = 'h';

str = strArr.join("");

2

Nếu bạn muốn thay thế các ký tự trong chuỗi, bạn nên tạo các chuỗi có thể thay đổi. Đây thực chất là các mảng ký tự. Bạn có thể tạo một nhà máy:

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

Sau đó, bạn có thể truy cập các ký tự và toàn bộ mảng chuyển thành chuỗi khi được sử dụng dưới dạng chuỗi:

  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

Tổng quát hóa câu trả lời của Afanasii Kurakin, chúng ta có:

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

Hãy mở rộng và giải thích cả biểu thức chính quy và chức năng thay thế:

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

Biểu thức chính quy .khớp chính xác với một ký tự. Làm gcho nó phù hợp với mọi nhân vật trong một vòng lặp for. Các replacerhàm được gọi cho cả hai nhân vật ban đầu và chỉ số về nơi nhân vật đó là trong chuỗi. Chúng tôi đưa ra một iftuyên bố đơn giản để xác định xem chúng tôi sẽ trở lại origCharhoặc newChar.


2

Bạn có thể mở rộng loại chuỗi để bao gồm phương thức chè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 "));

Sau đó, bạn có thể gọi hàm:


1

Tôi đã thực hiện một chức năng thực hiện một cái gì đó tương tự như những gì bạn yêu cầu, nó kiểm tra xem một ký tự trong chuỗi có nằm trong một mảng các ký tự không được phép hay không nếu nó thay thế nó bằng ''

    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

điều này có thể dễ dàng đạt được với 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"

1

Đây là một phiên bản tôi đã đưa ra nếu bạn muốn tạo kiểu cho các từ hoặc các ký tự riêng lẻ trong chỉ mục của chúng trong Reac / javascript.

replaceAt( yourArrayOfIndexes, yourString/orArrayOfStrings ) 

Ví dụ hoạt động: https://codesandbox.io/s/ov7zxp9mjq

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

Và đây là một phương pháp thay thế khác

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

Và ...

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

Tôi biết điều này là cũ nhưng giải pháp không hoạt động cho chỉ số tiêu cực vì vậy tôi thêm một bản vá cho nó. hy vọng nó sẽ giúp được ai đó

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

Hãy nói rằng bạn muốn thay thế Kthchỉ mục (chỉ mục dựa trên 0) bằng 'Z'. Bạn có thể sử dụng Regexđể làm điều này.

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

Bất cứ ý tưởng tại sao điều này được gắn thẻ không hữu ích?
ksp 17/03/2017

Tôi đã không kiểm tra xem regex này có hoạt động không, nhưng có lẽ nó bị hạ cấp bởi vì có thể tạo ra một chuỗi mới nhanh hơn rất nhiều so với việc biên dịch một máy trạng thái (biểu thức chính quy), rất tốn kém.
Felo Vilches

0

Bạn có thể sử dụng hàm sau để thay thế Characterhoặc Stringtại một vị trí cụ thể của Chuỗi. Để thay thế tất cả các trường hợp khớp sau đây sử dụng String.prototype.replaceAllMatches()chức năng.

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

Kiểm tra:

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

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

Đầu ra:

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

-1

Đây là giải pháp của tôi bằng cách sử dụng toán tử ternary và map. Dễ đọc hơn, kết thúc dễ bảo trì dễ hiểu hơn nếu bạn hỏi tôi.

Đó là nhiều hơn vào es6 và thực hành tốt nhất.

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

Các phương pháp ở đây rất phức tạp. Tôi sẽ làm theo cách này:

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

Điều này là đơn giản như nó được.


6
Không thực sự. Trong thực tế, nó sẽ thay thế sự xuất hiện đầu tiên của nhân vật. Vẫn sai.
Tomáš Zato - Tái lập Monica
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.