ChatGPT解决这个技术问题 Extra ChatGPT

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

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

var str = "hello world";

我需要类似的东西

str.replaceAt(0,"h");
奇怪的是 str[0] = 'x' 似乎没有抛出任何错误,但没有达到预期的效果!
@Michael,您将获得索引为0,将其设置为'x',该语句本身将返回新值; 'X'。但所有这些都不会改变原版,所以它完全有效,只是不是你所期望的。它不是参考
@Michael 如果 "use strict" 被激活,它会这样做:Uncaught TypeError: Cannot assign to read only property '0' of string 'hello world'(至少在 webkit 浏览器中)
Javascript 字符串是不可变的,它们不能“就地”修改,因此您不能修改单个字符。事实上,相同字符串的每一次出现都是一个对象。

C
Cem Kalyoncu

在 JavaScript 中,字符串是不可变的,这意味着您能做的最好的事情就是使用更改的内容创建一个新字符串,并将变量分配给它。

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

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

并像这样使用它:

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

请注意,扩展基本 JavaScript 类通常不是一个好主意。请改用普通的实用程序函数。
我必须问为什么?为此目的提供原型支持。
@CemKalyoncu:它会使代码与其他库一起玩不好。但我自己从来没有被那个咬过。
@alex:您是对的,您确实需要在执行此操作之前检查该功能是否存在。但即便如此,它也应该执行完全相同的操作。
我不同意,即使您检测到该函数是否存在,以后的库仍可能使用/创建一个类似的函数——两个坏主意使一个更糟。一般来说,永远不要玩弄其他人的代码(包括核心系统)。创建一个新函数。
Z
Zachary Christopoulos

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

function rep() { var str = 'Hello World'; str = setCharAt(str,4,'a');警报(str); } function setCharAt(str,index,chr) { if(index > str.length-1) return str;返回 str.substring(0,index) + chr + str.substring(index+1); }


我更喜欢这个解决方案,因为您可以用它替换单个字符。如果您只想替换一个字符,则获得最多支持的解决方案不起作用。它仅在替换两个字符时有效!此外,应将 substr 替换为许多其他评论中提到的 substring。
在我的测试中,这种方法是迄今为止最快的……如果您不需要验证 [index] 不大于字符串长度,甚至更快。修改:function setCharAt(str,idx,newChr){ return str.substring(0,idx)+newChr+str.substring(idx+1);}
@ScottTesler - 这个答案使用substring,而不是substr......并且在你的链接中它说这两个函数是“遗留”还是应该避免? ...substringsubstr 服务于 different purposes
@ashleedawg 看起来它不再被弃用了。
z
zendka

你不能。取位置前后的字符并连接成一个新字符串:

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

事实上,是的,你可以,但这将是一个矫枉过正。您可以设置一个正则表达式来跳过第一个索引 - 1 个字符并匹配索引处的字符。您可以将 String.replace 与该正则表达式一起使用来进行直接的就地替换。但这是矫枉过正。所以,在实践中你不能。但理论上,你可以。
@Ates:replace 函数不会进行就地替换,它会创建一个新字符串并返回它。
MDN 建议使用 String.prototype.substring 而不是 String.prototype.substr
c
colllin
str = str.split('');
str[3] = 'h';
str = str.join('');

清晰简单,但目前在使用 splitjoin 时不适用于表情符号(例如😀)
使用 es6,我认为 Array.from(str) 现在可能是一个更好的选择,但我带着这些知识来到这里,并从你那里学到了同样简洁的东西,所以谢谢你!
@DavidKamer 我迟到了,但似乎 Array.fromstr.split 慢得多。 blog.shovonhasan.com/…
@Green如果您的字符串包含表情符号,它可能是用户输入,因此我认为没有明显的理由使用此方法更改字符串中的字符,如果您想更改输入转换场景中的一部分,您应该使用 { 1} 使用正则表达式的方法。
@KadenSkinner 这是一个数组,因此您可以使用 str.splice(3, h.length, ...h.split(''))str.splice.apply(str, [3, h.length].concat(h.split(''))),但与 str.substring(0,3) + h + str.substring(5) 相比,这似乎很疯狂。
O
OzrenTkalcecKrznaric

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

METHOD1:使用两个子字符串拆分字符串并将字符填充在它们之间

METHOD2:将字符串转换为字符数组,替换一个数组成员并加入

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

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

我为此创建了一个小提琴,它是 here。有两个测试,TEST1(子字符串)和TEST2(数组转换)。

结果:

测试1:195ms

测试2:6ms

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

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

因此,关键在于为工作选择正确的工具。再次。


将您的测试移至 jsperf,结果大不相同:jsperf.com/string-replace-character。关键在于为工作选择合适的工具;)
@colllin:我完全同意。所以我几乎从字面上将测试从 jsfiddle 克隆到了 jsperf。但是,除了使用正确的工具之外,您还必须以正确的方式进行操作。注意这个问题,我们正在谈论如果我们必须在算法中进行相当多的替换会发生什么。具体示例包括 10000 次替换。这意味着 一个测试 应该包括 10000 个替换。因此,使用 jsperf,我得到了相当一致的结果,请参阅:jsperf.com/…
这就是我不喜欢javascript的原因。没有为这种频繁、直观、明显的用例提供服务。您会认为 javascript 的编写者会想到人们可能想要替换字符串中的字符,并且他们会决定将便利方法放入语言中。
@colllin 做了一些与 OzrenTkalcecKrznaric 不同的事情。 OzrenTkalcecKrznaric 假设字符串是静态的,并且可以在运行之前优化拆分。这不一定是真的。如果您必须在每次运行时拆分,那么子字符串方法在小字符串上的速度大约是两倍 - 4 倍,并且字符串越大越快。在我看来,这使得子字符串对于大多数用例来说是更好的实现,除非对大型静态字符串进行大量更改。
问题在于,在 test2 上,拆分和连接位于 for 循环之外,您可以在其中将单个字符替换与多个字符替换(不公平)进行比较,第一种方法对于单个替换更快,而第二种方法对于一个接一个的链式替换更好
F
Fabio Phms

使用向量通常是最有效的联系字符串。

我建议以下功能:

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[索引] = 字符;返回 a.join(""); } var str = "你好世界"; str = str.replaceAt(3, "#"); document.write(str);


这对大字符串不利,如果您可以使用 substr 来剪切它,则无需创建包含大量单元格的数组...
如果您需要更改大量字符,这很有用,而且很简单。
我在 jsperf 上创建了一个测试:jsperf.com/replace-character-by-index -- Substr 更快,并且从 32 字节到 100 KB 都保持一致。我对此表示赞同,尽管这让我很伤心,尽管这感觉更好,但 substr 是任何大小字符串的更好选择。
这是非常不理想的。
如果您知道要使用小字符串,这是一个很好的快速解决方案。如果您可以扩展原型,那么您可以在 2 行中实现类似的行为:Array.prototype.replace = function(index, val) { this[index] = val; return this; }; 'word'.split('').replace(1, '0').join(''); // returns 'w0rd'
c
colllin

在 Javascript 中,字符串是不可变的,所以你必须做类似的事情

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

用 'h' 替换 i 处 x 中的字符


V
Vikramaditya

函数 dothis() { var x = document.getElementById("x").value; var index = document.getElementById("index").value; var text = document.getElementById("text").value; var length = document.getElementById("length").value; var arr = x.split(""); arr.splice(索引,长度,文本); var 结果 = arr.join(""); document.getElementById('output').innerHTML = 结果;控制台.log(结果); } 做这个();

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

var x = "White Dog";
var arr = x.split(""); // ["W", "h", "i", "t", "e", " ", "D", "o", "g"]
arr.splice(6, 1, 'F');

/* 
  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. 
*/
var result = arr.join(""); // "White Fog"

投了赞成票,因为我发现额外的描述很有用,并且实现简单而强大。谢谢! :-D
Array.from 也可能是字符串到数组转换的好主意
是的 Array.from 也可以在这里使用。但是 Array.from 是在 ES2015 中添加的,并且在旧浏览器中不支持。另外,我个人更喜欢 split 函数,因为它可以更自由地使用字符串模式。
如果您只想替换 1 个字符,您可以使用 arr[6]='F'; 而不是 .splice()
@fabio-phms 在 answer above 中已经提出了您的建议。我只是从另一种观点来看,我们可以灵活地替换一个或多个字符。
A
Afanasii Kurakin

使用带有回调的 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
})

精美简单 - 不强制扩展原型或创建新功能的绝佳选择。谢谢!
S
Stephen Quan

概括 Afanasii Kurakin 的答案,我们有:

function replaceAt(str, index, ch) { return str.replace(/./g, (c, i) => i == index ? ch : c); } 让 str = 'Hello World'; str = replaceAt(str, 1, 'u');控制台.log(str); // 你好世界

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

function replaceAt(str, index, newChar) { function replacer(origChar, strIndex) { if (strIndex === index) return newChar;否则返回 origChar; } return str.replace(/./g, replacer); } 让 str = 'Hello World'; str = replaceAt(str, 1, 'u');控制台.log(str); // 你好世界

正则表达式 . 只匹配一个字符。 g 使其匹配 for 循环中的每个字符。给定原始字符和该字符在字符串中的位置索引,调用 replacer 函数。我们创建一个简单的 if 语句来确定我们是要返回 origChar 还是 newChar


A
Avi Cohen

var str = "你好世界";控制台.log(str); var arr = [...str]; arr[0] = "H"; str = arr.join("");控制台.log(str);


A
Aram Kocharyan

这与 Array.splice 类似:

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

M
Mehulkumar

你可以试试

var strArr = str.split("");

strArr[0] = 'h';

str = strArr.join("");

这里不多解释。你能解释一下它是如何工作的吗? “0”应该是我要更改的索引吗?
@SethEden 是的,“0”应该是您要更改的索引。
S
Scrimothy

@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 类型功能一致。
M
Magne

你可以试试

var strArr = str.split("");

strArr[0] = 'h';

str = strArr.join("");

查看此功能以了解打印步骤

steps(3)
//       '#  '
//       '## '
//       '###'

function steps(n, i = 0, arr = Array(n).fill(' ').join('')) {
  if (i === n) {
    return;
  }

  str = arr.split('');
  str[i] = '#';
  str = str.join('');
  console.log(str);

  steps(n, (i = i + 1), str);
}


J
Jan Turoň

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

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

M
Madmadi

这很容易通过 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"

就当代 JavaScript 而言,到 2022 年,这是迄今为止最好的答案。
m
mbadeveloper

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

String.prototype.append = function (index,value) { return this.slice(0,index) + value + this.slice(index); }; var s = "新字符串";警报(s.append(4,“完成”));

然后就可以调用函数了:


G
Gyum Fox

使用 spread syntax,您可以将字符串转换为数组,在给定位置分配字符,然后再转换回字符串:

const str = "你好世界";函数 replaceAt(s, i, c) { const arr = [...s]; // 将字符串转换为数组 arr[i] = c; // 将 char c 设置在 pos i return arr.join(''); // 返回字符串 } // 打印“你好世界” console.log(replaceAt(str, 1, 'a'));


我会小心地将它放入这样的函数中。因为不可避免地有人会在循环中运行该函数。在这种情况下,与他们在需要时必须简单地编写“转换为数组”和“加入”自己相比,这将是非常不理想的。然后他们自然会把它放在循环之外。
M
MD SHAYON

您可以首先使用子字符串函数连接目标索引之前和目标索引之后的文本,然后与潜在的字符或字符串连接。这个更好

const myString = "Hello world";
const index = 3;
const stringBeforeIndex = myString.substring(0, index);
const stringAfterIndex = myString.substring(index + 1);
const replaceChar = "X";
myString = stringBeforeIndex + replaceChar + stringAfterIndex;
console.log("New string - ", myString)

或者

const myString = "Hello world";
let index = 3;
myString =  myString.substring(0, index) + "X" + myString.substring(index + 1);

r
revelt

我做了一个类似于你问的函数,它检查字符串中的一个字符是否在一个不允许的字符数组中,如果它用''替换它

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

M
Matt Wright

如果您想在 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;
}

k
karlo1zg

这是我使用三元和映射运算符的解决方案。如果你问我,更易读、更易维护的目的更容易理解。

它更多地涉及 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(`新字符串:${newStr}`); }


j
jonas kjellerup

我知道这很旧,但是该解决方案不适用于负索引,因此我为其添加了一个补丁。希望它可以帮助某人

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

}

k
ksp

假设您想用 'Z' 替换 Kth 索引(基于 0 的索引)。您可以使用 Regex 来执行此操作。

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

知道为什么这个标签没有用吗?
我没有检查这个正则表达式是否有效,但它可能被否决了,因为创建一个新字符串可能比编译一个非常昂贵的状态机(正则表达式)快得多。
Y
Yash

您可以使用以下函数在字符串的特定位置替换 CharacterString。要替换以下所有匹配案例,请使用 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.**

A
Alexandre Daubricourt

我使用负索引的安全方法

/**
 * @param {string} str 
 * @param {number} index 
 * @param {string} replacement 
 * @returns {string}
 */
static replaceAt (str, index, replacement)
{
    if (index < 0) index = str.length + index
    if (index < 0 || index >= str.length) throw new Error(`Index (${index}) out of bounds "${str}"`)
    return str.substring(0, index) + replacement + str.substring(index + 1)
}

像这样使用它:

replaceAt('my string', -1, 'G') // 'my strinG'
replaceAt('my string', 2, 'yy') // 'myyystring'
replaceAt('my string', 22, 'yy') // Uncaught Error: Index (22) out of bounds "my string"

m
mikey

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

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

这很简单。


实际上不是。事实上,它将替换第一次出现的字符。还是错了。