在 C# 中编辑字符串中的字符

问题描述 投票:0回答:12

在 C# 中编辑字符串中的字符最简洁的方法是什么?

C# 中与 C++ 相同的内容是什么:

std::string myString = "boom";
myString[0] = "d";
c# .net c++ string
12个回答
32
投票

请使用

StringBuilder
代替。

字符串是不可变的,如 MSDN 所描述的那样:

字符串是不可变的——其内容 字符串对象无法更改 在创建对象之后,虽然 语法让它看起来好像你 可以做到这一点。

所以你想要这样的东西:

 StringBuilder sb = new StringBuilder("Bello World!");
 sb[0] = 'H';
 string str = sb.ToString();

15
投票

决定将我的感受记录在两种最规范的方法中,再加上一种我认为没有代表性的方法;这是我发现的(发布版本):

ReplaceAtChars:86ms
ReplaceAtSubstring:258ms
ReplaceAtStringBuilder:161ms

显然,Char 数组方法迄今为止在运行时得到了最佳优化。这实际上表明当前的leading答案(StringBuilder)可能不是best答案。

这是我使用的测试:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("ReplaceAtChars: " + new Stopwatch().Time(() => "test".ReplaceAtChars(1, 'E').ReplaceAtChars(3, 'T'), 1000000) + "ms");
        Console.WriteLine("ReplaceAtSubstring: " + new Stopwatch().Time(() => "test".ReplaceAtSubstring(1, 'E').ReplaceAtSubstring(3, 'T'), 1000000) + "ms");
        Console.WriteLine("ReplaceAtStringBuilder: " + new Stopwatch().Time(() => "test".ReplaceAtStringBuilder(1, 'E').ReplaceAtStringBuilder(3, 'T'), 1000000) + "ms");
    }
}

public static class ReplaceAtExtensions
{
    public static string ReplaceAtChars(this string source, int index, char replacement)
    {
        var temp = source.ToCharArray();
        temp[index] = replacement;
        return new String(temp);
    }

    public static string ReplaceAtStringBuilder(this string source, int index, char replacement)
    {
        var sb = new StringBuilder(source);
        sb[index] = replacement;
        return sb.ToString();
    }

    public static string ReplaceAtSubstring(this string source, int index, char replacement)
    {
        return source.Substring(0, index) + replacement + source.Substring(index + 1);
    }
}

public static class StopwatchExtensions
{
    public static long Time(this Stopwatch sw, Action action, int iterations)
    {
        sw.Reset();
        sw.Start();
        for (int i = 0; i < iterations; i++)
        {
            action();
        }
        sw.Stop();

        return sw.ElapsedMilliseconds;
    }
}

8
投票

.Net 中的字符串是不可变的。 这意味着您无法编辑它们。 你所能做的就是制作新的。 你必须做这样的事情:

string myString = "boom";
myString = "d" + myString.Substring(1);

8
投票

字符串是不可变的,所以你不能仅仅改变它。

您可以从字符串中获取 char[],进行更改,然后从更改后的数组中创建一个新字符串。

您可以使用诸如替换之类的东西,尽管它们不能让您像 C 那样控制每个字符的基础。他们还会在每次更改时创建一个新字符串,其中 char[] 样式允许您进行所有更改,然后从中创建一个新字符串。


5
投票

你不能,因为字符串是不可变的。

您始终可以推出自己的扩展方法来执行类似的操作:

public static string ReplaceAtIndex(this string original, 
    int index, char character)
{
    char[] temp = original.ToCharArray();
    temp[index] = character;
    return new String(temp);
}

并称其为:

string newString = myString.ReplaceAtIndex(0, 'd');

4
投票

正如 Brian 所说,使用

StringBuilder
,而不是:

string myString = "boom";
StringBuilder myStringBuilder = new StringBuilder(myString);
myStringBuilder[0] = 'd';
// Whatever else you're going to do to it

每当您再次需要字符串时,请致电

myStringBuilder.ToString()


3
投票
string myString = "boom";
char[] arr = myString.ToCharArray();
arr[0] = 'd';
myString = new String(arr);

3
投票
string myString = "boom";
char[] myChars = myString.ToCharArray();
myChars[0] = 'd';
myString = new String(myChars);

3
投票

C# 中的字符串是不可变的。 使用 StringBuilder 类或字符数组。

StringBuilder sb = new StringBuilder("boom");
sb[0] = 'd';

IIRC,.NET 使用所谓的字符串池。 每次创建新的字符串文字时,它都会作为字符串池的一部分存储在内存中。 如果您创建与字符串池中的字符串匹配的第二个字符串,则两个变量将引用相同的内存。

当您尝试执行类似使用 .NET 中的字符串将“b”字符替换为“d”字符的操作时,您的程序实际上是在字符串池中创建第二个字符串,其值为“doom”,尽管从你的角度来看,这似乎根本没有发生。 通过阅读代码,人们会认为该角色正在被替换。

我提出这个问题是因为我一直遇到这个问题,人们经常问为什么当字符串可以做同样的事情时他们应该使用 StringBuilder。 从技术上来说它不能,但它的设计方式看起来好像可以。


2
投票

这是我整理的一个有趣的。现在,请记住这不是很有效,特别是对于简单的替换。然而,编写起来很有趣,并且适合于具有相当可读的使用模式。它还强调了一个鲜为人知的事实:String 实现了 IEnumerable。

public static class LinqToStrings
{
    public static IQueryable<char> LinqReplace(this string source, int startIndex, int length, string replacement)
    {
        var querySource = source.AsQueryable();
        return querySource.LinqReplace(startIndex, length, replacement);
    }

    public static IQueryable<char> LinqReplace(this IQueryable<char> source, int startIndex, int length, string replacement)
    {
        var querySource = source.AsQueryable();
        return querySource.Take(startIndex).Concat(replacement).Concat(querySource.Skip(startIndex + length));
    }

    public static string AsString(this IQueryable<char> source)
    {
        return new string(source.ToArray());
    }
}

这里有一些示例用法:

public void test()
{
    var test = "test";
    Console.WriteLine("Old: " + test);
    Console.WriteLine("New: " + test.LinqReplace(0, 4, "SOMEPIG")
                                    .LinqReplace(4, 0, "terrific")
                                    .AsString());
}

输出:

旧:测试
新:SOMEterrificPIG

同一方法的另一个版本,速度并没有那么慢,很简单,使用 Substring:

public static string ReplaceAt(this string source, int startIndex, int length, string replacement)
{
    return source.Substring(0, startIndex) + replacement + source.Substring(startIndex + length);
}

在一个精彩的示例中,说明为什么您应该分析代码,以及为什么您可能不应该在生产代码中使用我的 LinqToStrings 实现,这里有一个计时测试:

Console.WriteLine("Using LinqToStrings: " + new Stopwatch().Time(() => "test".LinqReplace(0, 4, "SOMEPIG").LinqReplace(4, 0, "terrific").AsString(), 1000)); Console.WriteLine("Using Substrings: " + new Stopwatch().Time(() => "test".ReplaceAt(0, 4, "SOMEPIG").ReplaceAt(4, 0, "terrific"), 1000));

它测量 1,000 次迭代中的计时器滴答声,产生以下输出:

使用 LinqToStrings:3,818,953 使用子字符串:1,157
    

1
投票
尝试使用 string.replace

http://msdn.microsoft.com/en-us/library/fk49wtc1.aspx

可能是您最干净、最简单的方法。


0
投票
string str = "Hello, world!"; ReadOnlySpan<char> span = str.AsSpan(); Memory<char> memory; fixed (char* pointer = &span.GetPinnableReference()) { using var memoryManager = new UnmanagedMemoryManager<char>(pointer, span.Length); memory = memoryManager.Memory; } memory.Span[0] = 'A'; Console.WriteLine(str); // Output: Aello, world!
使用这个跨度黑客
首次安装 NuGet 包 Pipelines.Sockets.Unofficial

适用于.NET 9

© www.soinside.com 2019 - 2024. All rights reserved.