在字符串中替换给定索引处的字符?

139

String类中没有ReplaceAt()方法,我需要一个能够满足我的需求的函数,但是我有点不确定该如何实现。虽然这可能会导致CPU开销较大,但是由于字符串大小很小,所以这并不成问题。


4
你是否本意说“没有”而不是“有呢”? :) - Abbas
7个回答

238
使用 StringBuilder:
StringBuilder sb = new StringBuilder(theString);
sb[index] = newChar;
theString = sb.ToString();

5
@Jason94,我不确定这种方法是否比Jon的答案中使用ToCharArray更有效,你应该运行测试来看哪个更快。 - Thomas Levesque
20
我进行了一个小型的基准测试,运行了100,000次迭代,其中ToCharArray至少比其它方法快2倍。 - Matteo Migliore
1
使用对象初始化器,您可以将其变成一行代码:new StringBuilder(theString) {[index] = newChar}.ToString(); - Teun

96

最简单的方法可能是这样的:

public static string ReplaceAt(this string input, int index, char newChar)
{
    if (input == null)
    {
        throw new ArgumentNullException("input");
    }
    char[] chars = input.ToCharArray();
    chars[index] = newChar;
    return new string(chars);
}

现在这是一个扩展方法,所以您可以使用:

var foo = "hello".ReplaceAt(2, 'x');
Console.WriteLine(foo); // hexlo

希望能想出一种只需要制作一个数据副本的方法,而不是现在这样需要两个,但我不确定有什么方法可以做到。也许这样做可以实现:

public static string ReplaceAt(this string input, int index, char newChar)
{
    if (input == null)
    {
        throw new ArgumentNullException("input");
    }
    StringBuilder builder = new StringBuilder(input);
    builder[index] = newChar;
    return builder.ToString();
}

我认为这完全取决于你正在使用的框架版本。


6
+1使其成为扩展方法。正如已接受答案的评论和其他答案中提到的那样,ToCharArray()方法比StringBuilder方法更快。 还有一个可能的改进:检查输入计数是否大于index-1并且index大于等于0,否则在执行chars[index]或builder[index]时会引发异常。 - sth_Weird

40
string s = "ihj";
char[] array = s.ToCharArray();
array[1] = 'p';
s = new string(array);

3
被接受的答案下面的评论表明,这种方法的速度是原来的两倍。 - Dejan
更快更好。 - juFo

6

字符串是不可变对象,因此您无法替换字符串中的某个字符。 您可以做的是创建一个用给定字符替换的新字符串。

但是,如果要创建一个新字符串,为什么不使用 StringBuilder:

string s = "abc";
StringBuilder sb = new StringBuilder(s);
sb[1] = 'x';
string newS = sb.ToString();

//newS = "axc";

4

我突然需要完成这个任务,然后发现了这个主题。所以,这是我的Linq风格变体:

public static class Extensions
{
    public static string ReplaceAt(this string value, int index, char newchar)
    {
        if (value.Length <= index)
            return value;
        else
            return string.Concat(value.Select((c, i) => i == index ? newchar : c));
    }
}

然后,举个例子:

string instr = "Replace$dollar";
string outstr = instr.ReplaceAt(7, ' ');

最终我需要使用.Net Framework 2,因此我使用了一个StringBuilder类的变体。

这样做对于长字符串来说会很慢,为什么不使用StringBuilderToCharArray解决方案呢?虽然相比于StringBuilder可能少了一次字符串复制,但我怀疑内部会发生很多事情。 - ToolmakerSteve

-2
如果您的项目(.csproj)允许不安全代码,那么这可能是更快的解决方案:
namespace System
{
  public static class StringExt
  {
    public static unsafe void ReplaceAt(this string source, int index, char value)
    {
        if (source == null)
            throw new ArgumentNullException("source");

        if (index < 0 || index >= source.Length)
            throw new IndexOutOfRangeException("invalid index value");

        fixed (char* ptr = source)
        {
            ptr[index] = value;
        }
    }
  }
}

您可以将其用作 String 对象的扩展方法。


4
当然,这违反了string的语义 - 影响了对该对象的任何其他引用,从而使 string 对象 不可变 的文档无效/相矛盾。对一个内置类这样做是极不可靠的(强烈的代码味道)。需要在其上添加巨大的警告注释。就我个人而言,我不会这样做。如果有人需要一个可变的字符串,则应创建一个适当的类,子类或包装一个char [] - ToolmakerSteve

-4
public string ReplaceChar(string sourceString, char newChar, int charIndex)
    {
        try
        {
            // if the sourceString exists
            if (!String.IsNullOrEmpty(sourceString))
            {
                // verify the lenght is in range
                if (charIndex < sourceString.Length)
                {
                    // Get the oldChar
                    char oldChar = sourceString[charIndex];

                    // Replace out the char  ***WARNING - THIS CODE IS WRONG - it replaces ALL occurrences of oldChar in string!!!***
                    sourceString.Replace(oldChar, newChar);
                }
            }
        }
        catch (Exception error)
        {
            // for debugging only
            string err = error.ToString();
        }

        // return value
        return sourceString;
    }

1
sourceString.Replace(oldChar, newChar) 会替换字符串中所有出现的 oldChar,而不仅仅是 charIndex 处的字符。 - EventHorizon
string err = error.ToString(); 为什么? - Stefan Michev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接