在 C# 中编辑字符串中的字符最简洁的方法是什么?
C# 中与 C++ 相同的内容是什么:
std::string myString = "boom";
myString[0] = "d";
请使用
StringBuilder
代替。
字符串是不可变的,如 MSDN 所描述的那样:
字符串是不可变的——其内容 字符串对象无法更改 在创建对象之后,虽然 语法让它看起来好像你 可以做到这一点。
所以你想要这样的东西:
StringBuilder sb = new StringBuilder("Bello World!");
sb[0] = 'H';
string str = sb.ToString();
决定将我的感受记录在两种最规范的方法中,再加上一种我认为没有代表性的方法;这是我发现的(发布版本):
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;
}
}
.Net 中的字符串是不可变的。 这意味着您无法编辑它们。 你所能做的就是制作新的。 你必须做这样的事情:
string myString = "boom";
myString = "d" + myString.Substring(1);
字符串是不可变的,所以你不能仅仅改变它。
您可以从字符串中获取 char[],进行更改,然后从更改后的数组中创建一个新字符串。
您可以使用诸如替换之类的东西,尽管它们不能让您像 C 那样控制每个字符的基础。他们还会在每次更改时创建一个新字符串,其中 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);
C# 中的字符串是不可变的。 使用 StringBuilder 类或字符数组。
StringBuilder sb = new StringBuilder("boom");
sb[0] = 'd';
IIRC,.NET 使用所谓的字符串池。 每次创建新的字符串文字时,它都会作为字符串池的一部分存储在内存中。 如果您创建与字符串池中的字符串匹配的第二个字符串,则两个变量将引用相同的内存。
当您尝试执行类似使用 .NET 中的字符串将“b”字符替换为“d”字符的操作时,您的程序实际上是在字符串池中创建第二个字符串,其值为“doom”,尽管从你的角度来看,这似乎根本没有发生。 通过阅读代码,人们会认为该角色正在被替换。
我提出这个问题是因为我一直遇到这个问题,人们经常问为什么当字符串可以做同样的事情时他们应该使用 StringBuilder。 从技术上来说它不能,但它的设计方式看起来好像可以。
这是我整理的一个有趣的。现在,请记住这不是很有效,特别是对于简单的替换。然而,编写起来很有趣,并且适合于具有相当可读的使用模式。它还强调了一个鲜为人知的事实: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
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