如何在JavaScript中的特定索引处替换字符?


544

我有一个字符串,假设Hello world我需要替换索引3处的char。如何通过指定索引来替换char?

var str = "hello world";

我需要类似的东西

str.replaceAt(0,"h");

130
奇怪的是str[0] = 'x'似乎没有引发任何错误,但没有达到预期的效果!
迈克尔

6
@Michael,您将获得索引为0,将其设置为“ x”,该语句本身将返回新值;'X'。但是所有这些都不会改变原始数据,因此它完全有效,只是没有您期望的那样。它不是参考
Paul Scheltema

8
@Michael是否"use strict"被激活:(Uncaught TypeError: Cannot assign to read only property '0' of string 'hello world'至少在Webkit浏览器中)
JanTuroň2016年

1
Javascript字符串是不可变的,它们不能“就地”修改,因此您不能修改单个字符。实际上,同一字符串的每次出现都是一个对象。
马丁·谢弗

好吧,请看答案:D
Martijn Scheffer

Answers:


611

在JavaScript中,字符串是不可变的,这意味着最好的办法是使用更改后的内容创建新的字符串,然后将变量分配为指向该字符串。

您需要自己定义replaceAt()函数:

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

并像这样使用它:

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

101
请注意,扩展基本JavaScript类通常不是一个好主意。请改用普通的实用程序函数。
Ates Goral

86
我必须问为什么?为此提供了原型支持。
Cem Kalyoncu

30
@CemKalyoncu:它可以使代码与其他库一起播放不良。但是我从来没有被自己咬过。
Alex

6
@alex:您是对的,您确实需要在执行该功能之前检查该功能是否存在。但是即使这样做,它也应该执行完全相同的操作。
Cem Kalyoncu

80
我不同意,即使您检测到该函数是否存在,以后的库仍可能使用/创建类似的函数-2个坏主意使一个更差的主意。通常,永远不要玩弄别人的代码(包括核心系统)。创建一个新功能。
martyman 2012年

93

replaceAtJavaScript中没有函数。您可以使用以下代码在指定位置替换任何字符串中的任何字符:

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>



我更喜欢这种解决方案,因为您可以用它替换单个字符。如果您只想替换一个字符,则投票数最多的解决方案将不起作用。仅在替换两个字符时有效!同样,应将substr替换为许多其他注释中提到的substring。
gignu

74

你不能 将位置前后的字符合并为一个新字符串:

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

实际上,是的,您可以,但是这太过分了。您可以设置一个正则表达式以跳过第一个索引-1个字符并匹配索引处的字符。您可以将String.replace与该正则表达式一起使用以进行直接就地替换。但这太过分了。因此,实际上您不能这样做。但从理论上讲,您可以。
Ates Goral

12
@Ates:replace函数不会进行就地替换,它会创建一个新字符串并返回它。
Guffa

2
MDN建议使用String.prototype.substringString.prototype.substr
Mikemike

33

这里有很多答案,并且所有答案都基于两种方法:

  • 方法1:使用两个子字符串拆分字符串,并将它们之间的字符填充
  • 方法2:将字符串转换为字符数组,替换一个数组成员并将其加入

就个人而言,我将在不同情况下使用这两种方法。让我解释。

@FabioPhms:您的方法是我最初使用的方法,我担心它对包含许多字符的字符串不利。但是,问题是有多少个字符?我在10个“ lorem ipsum”段落中对其进行了测试,并花费了几毫秒的时间。然后我在大10倍的弦上进行了测试-确实没有太大的区别。嗯

@ vsync,@ Cory Mawhorter:您的评论是明确的;但是,什么是大字符串呢?我同意对于32 ... 100kb的性能应该更好,并且应该对这一字符替换操作使用substring-variant。

但是,如果我不得不进行很多替换,将会发生什么?

我需要执行自己的测试以证明在这种情况下更快。假设我们有一种算法,可以处理由1000个字符组成的较短字符串。我们预计该字符串中的每个字符平均将被替换100次左右。因此,用于测试类似代码的代码是:

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

我为此制造了一个小提琴,就在这里。有两个测试,TEST1(子字符串)和TEST2(数组转换)。

结果:

  • TEST1:195ms
  • TEST2:6ms

数组转换似乎比子字符串高2个数量级!所以-这里到底发生了什么?

实际发生的情况是,TEST2中的所有操作都是使用数组之类的赋值表达式在数组本身上完成的strarr2[p] = n。与大字符串上的子字符串相比,分配确实非常快,而且很明显,它会赢。

因此,这全都在于为工作选择合适的工具。再次。


7
将您的测试移至jsperf,结果截然不同:jsperf.com/string-replace-character。这全都在于为工作选择合适的工具;)
colllin 2014年

1
@colllin:我绝对同意。因此,我几乎从字面上将测试从jsfiddle克隆到了jsperf。但是,除了使用正确的工具外,您还必须以正确的方式进行操作。注意这个问题,我们正在谈论如果必须在算法中进行很多替换的话会发生什么。具体示例包括10000个替换项。这意味着一个测试应包括10000个替换项。因此,使用jsperf,我得到了相当一致的结果,请参阅:jsperf.com/…
OzrenTkalcecKrznaric 2014年

1
这就是为什么我不喜欢javascript的原因。没有规定这种频繁,直观,明显的用例。您可能认为javascript的编写者会想到人们可能希望替换字符串中的字符,并且他们决定将便利方法放入该语言中。
ahnbizcad 2015年

1
@colllin与OzrenTkalcecKrznaric有所不同。OzrenTkalcecKrznaric假设字符串是静态的,并且可以在运行之前优化拆分。这不一定是正确的。如果必须在每次运行时进行拆分,则子字符串方法在小字符串上的速度大约要快两倍-4倍,而字符串越大则速度只会更快。在我看来,这使子字符串对于大多数用例而言都是更好的实现,禁止在大型静态​​字符串上进行大量更改。
WiR3D

3
问题在于,在test2上,split和join在for循环之外,您在其中将单个char替换与多个char替换进行比较(不公平),第一种方法对于单个替换比较快,而第二种方法对于链式替换则更好。
ΘεόφιλοςΜουρατίδης

32

使用向量通常是联系String最有效的方法。

我建议以下功能:

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

运行以下代码段:

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
这对于大字符串是不利的,如果您可以使用substr剪切它,则无需创建带有大量单元的数组……
vsync

1
如果您需要更改很多字符,则非常有用,而且很简单。
羊皮的

6
我在jsperf上创建了一个测试:jsperf.com/replace-character-by-index-Substr速度更快,并且从32bytes到100kb都是一致的。我对此表示赞同,尽管这听起来更好,但substr是任何大小的字符串的更好选择。
2013年

这是非常不理想的。
Radko Dinev 2014年

如果您知道要使用小字符串,这是一个很好的快速解决方案。如果您可以扩展原型,那么您可以分两行实现类似的行为:Array.prototype.replace = function(index, val) { this[index] = val; return this; }; 'word'.split('').replace(1, '0').join(''); // returns 'w0rd'
Michael Plautz

29

在Javascript中,字符串是不可变的,因此您必须执行以下操作

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

将“ i”处的x中的字符替换为“ h”


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

4
简单明了的,但目前使用时也不会通过表情符号在工作(如😀)splitjoin
格林

1
使用es6,我认为Array.from(str)现在可能是一个更好的选择,但是我带着这些知识来到这里,并从您那里学到了一些简洁的知识,谢谢!
David Kamer

7

一线使用String.replace和回调(不支持表情符号):

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

解释:

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

此方法适用于较小长度的字符串,但对于较大的文本可能较慢。

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:感谢您的出色回答!

我还对其进行了稍微调整,使其更类似于Array.splice方法(并考虑了@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!"

不知道为什么这被否决了。这是一个合法的答案。它按指示工作。并且它与Array.splice类型功能一致。
Scrimothy


3

你可以试试

var strArr = str.split("");

strArr[0] = 'h';

str = strArr.join("");

2

如果要替换字符串中的字符,则应创建可变字符串。这些本质上是字符数组。您可以创建一个工厂:

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

然后,您可以访问字符,并且整个数组用作字符串时会转换为字符串:

  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的答案,我们有:

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

让我们扩展并解释正则表达式和replacer函数:

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

正则表达式.恰好匹配一个字符。将g使得每一个字符的匹配循环。replacer给定原始字符和该字符在字符串中位置的索引,将调用该函数。我们做一个简单的if语句来确定是否要返回origCharnewChar


2

您可以扩展字符串类型以包括inset方法:

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

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

然后可以调用该函数:


1

我做了一个功能类似于您的要求的函数,它检查字符串中的字符是否在不允许的字符数组中,如果它被替换为”

    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

使用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

如果您想在react / javascript中的单词或单个字符的索引处设置样式,这是我想到的一个版本。

replaceAt( yourArrayOfIndexes, yourString/orArrayOfStrings ) 

工作示例:https//codesandbox.io/s/ov7zxp9mjq

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

这是另一种替代方法

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

还有一个

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

我知道这很旧,但是该解决方案不适用于负索引,因此我向其添加了补丁。希望对别人有帮助

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

假设您要用替换Kth索引(基于0的索引)'Z'。您可以Regex用来做到这一点。

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

知道为什么这个标记没有用吗?
ksp

我没有检查过此正则表达式是否有效,但也许它被否决了,因为创建新字符串可能比编译状态机(正则表达式)要快得多,后者非常昂贵。
Felo Vilches

0

您可以使用以下函数替换String CharacterString在String的特定位置。要替换以下所有匹配项,请使用String.prototype.replaceAllMatches()函数。

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

测试:

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

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

输出:

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

-1

这是我使用三元和映射运算符的解决方案。如果您问我,则更具可读性,可维护性的一端更易于理解。

es6和最佳实践中有更多内容。

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

这里的方法很复杂。我会这样:

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

这很简单。


6
实际上不是。实际上,它将替换字符的第一次出现。还是错。
托马什Zato -恢复莫妮卡
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.