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

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

C ++中C#的等价物是什么:

std::string myString = "boom"; myString[0] = "d"; 

决定按照两种最规范的方法来判断我的感受,加上一个我没有代表的方式; 这是我发现的(发布版本):

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

显然,Chararrays方法是运行时最佳优化的。 这实际上表明当前的主要答案(StringBuilder)可能不是最好的答案。

这是我用过的测试:

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

请改用StringBuilder

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

字符串是不可变的 – 创建对象后,字符串对象的内容无法更改,尽管语法使其看起来好像可以执行此操作。

所以你想要这样的东西:

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

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

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

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

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

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

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

您可以随时使用自己的扩展方法来执行类似的操作:

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

正如Brian所说,使用StringBuilder ,而不是:

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

每当你再次需要字符串时,调用myStringBuilder.ToString()

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

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

 public static class LinqToStrings { public static IQueryable LinqReplace(this string source, int startIndex, int length, string replacement) { var querySource = source.AsQueryable(); return querySource.LinqReplace(startIndex, length, replacement); } public static IQueryable LinqReplace(this IQueryable 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 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

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

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

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

当您尝试执行类似于使用.NET中的字符串替换’b’字符和’d’字符的操作时,您的程序实际上是在字符串池中创建第二个字符串,其值为“doom”,尽管从你的观点似乎并没有发生这种情况。 通过阅读代码,可以假设角色正在被替换。

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

尝试使用string.replace

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

可能是你最干净,最简单的方式。