What's the cleanest way of editing the characters in a string in C#?
What's the C# equivalent of this in C++:
std::string myString = "boom";
myString[0] = "d";
What's the cleanest way of editing the characters in a string in C#?
What's the C# equivalent of this in C++:
std::string myString = "boom";
myString[0] = "d";
Strings in .Net are immutable. That means you can't edit them. All you can do is make new ones. You have to do something like this:
string myString = "boom";
myString = "d" + myString.Substring(1);
Try using string.replace
http://msdn.microsoft.com/en-us/library/fk49wtc1.aspx
Probably your cleanest, easiest way.
Strings are immutable, so you can't just change it.
You could get a char[] from the string, make your changes, and make a new string from the altered array.
You could use things like replace, although they don't give you control over the per-char basis as C like. They also will make a new string with every change, where the char[] style allows you to make all changes and then make a new string from it.
Use a StringBuilder
instead.
string is immutable as described by MSDN:
Strings are immutable--the contents of a string object cannot be changed after the object is created, although the syntax makes it appear as if you can do this.
So you want something like:
StringBuilder sb = new StringBuilder("Bello World!");
sb[0] = 'H';
string str = sb.ToString();
You can't since strings are immutable.
You could always roll your own extension method to do something similar:
public static string ReplaceAtIndex(this string original,
int index, char character)
{
char[] temp = original.ToCharArray();
temp[index] = character;
return new String(temp);
}
And call it like:
string newString = myString.ReplaceAtIndex(0, 'd');
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);
As Brian said, use a StringBuilder
, instead:
string myString = "boom";
StringBuilder myStringBuilder = new StringBuilder(myString);
myStringBuilder[0] = 'd';
// Whatever else you're going to do to it
Whenever you need the string again, call myStringBuilder.ToString()
Here's a fun one I put together. Now, please bear in mind this is not very efficient, especially for simple replacements. However, it was fun to write and lends itself to a fairly readable usage pattern. It also highlights the little known fact that String implements 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());
}
}
And here's some example usage:
public void test()
{
var test = "test";
Console.WriteLine("Old: " + test);
Console.WriteLine("New: " + test.LinqReplace(0, 4, "SOMEPIG")
.LinqReplace(4, 0, "terrific")
.AsString());
}
Outputs:
Old: test New: SOMEterrificPIG
Another version of that same approach, which is not so horrifically slow is straightforward using Substring:
public static string ReplaceAt(this string source, int startIndex, int length, string replacement)
{
return source.Substring(0, startIndex) + replacement + source.Substring(startIndex + length);
}
And in a wonderful example of why you should profile your code, and why you probably should not use my LinqToStrings implementation in production code, here's a timing test:
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));
Which measures timer ticks in 1,000 iterations, producing this output:
Using LinqToStrings: 3,818,953 Using Substrings: 1,157
Decided to time what I felt where the two most canonical approaches, plus one I threw in as unrepresented; here's what I found (Release build):
ReplaceAtChars: 86ms ReplaceAtSubstring: 258ms ReplaceAtStringBuilder: 161ms
Clearly the Char array approach is by far best optimized by the runtime. Which actually suggests that the current leading answer (StringBuilder) is likely not the best answer.
And here was the test I used:
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;
}
}
Strings are immutable in C#. Use the StringBuilder class or a character array.
StringBuilder sb = new StringBuilder("boom");
sb[0] = 'd';
IIRC, .NET uses what is called String Pooling. Every time a new string literal is created, it is stored in memory as part of the string pool. If you create a second string that matches a string in the string pool, both variables will reference the same memory.
When you try to do an operation like you did to replace the 'b' character with a 'd' character using strings in .NET, your program is actually creating a second string in the string pool with the value "doom", although from your perspective it does not appear as if this is happening at all. By reading the code, one would assume that the character is being replaced.
I brought this up because I encounter this question all the time, and people often ask why they should be using the StringBuilder when a string can do the same thing. Well technically it can't, but it's designed in a way to appear as if it can.