Editing Mutable String in C # /. NET
I want to take and edit a string in place in a .NET application. I know it StringBuilder
allows me to do in-place add, insert and replace, but that doesn't make it easy to do things like this:
while (script.IndexOf("@Unique", StringComparison.InvariantCultureIgnoreCase) != -1)
{
int Location = script.IndexOf("@Unique", StringComparison.InvariantCultureIgnoreCase);
script = script.Remove(Location, 7);
script = script.Insert(Location, Guid.NewGuid().ToString());
}
As not IndexOf
in StringBuilder
. Does anyone have an efficient way to edit text information in place?
Edit # 1: Modified sample to make it more obvious that each "replacement" should have a different result.
source to share
If your code is really that simple, why not just use one of the built-in methods Replace
, either on string
, StringBuilder
or Regex
?
EDIT FOLLOWING COMMENT ...
You can replace each occurrence with a distinct value using one of the overloads Regex.Replace
that takes an argumentMatchEvaluator
:
string foo = "blah blah @Unique blah @Unique blah blah @Unique blah";
// replace each occurrence of "@Unique" with a separate guid
string bar = Regex.Replace(foo, "@Unique",
new MatchEvaluator(m => Guid.NewGuid().ToString()),
RegexOptions.IgnoreCase));
source to share
The StringBuilder is designed in such a way that you can easily add to it, but with a tradeoff that's hard to find in it - and all the more difficult (i.e. slower) to index it. If you need to change some characters "in place", it is best to do so in the resulting string.
But from your question it's hard to figure out which is the correct answer for you, I feel like you don't need to replace the place in place in the StringBuilder and the problem is elsewhere / you are doing something else wrong.
source to share
User Dennis provided an IndexOf extension method for StringBuilder . Thus, you should be able to use StringBuilder this way.
source to share
Can you use line splitting to do this efficiently?
Something like:
var sections = "a-@Unique-b-@Unique-c".Split(new string[] { "@Unique" }, StringSplitOptions.None);
int i;
StringBuilder builder = new StringBuilder();
for(i = 0; i < sections.Length - 1; i++)
{
builder.Append(sections[i]);
builder.Append(Guid.NewGuid().ToString());
}
builder.Append(sections[i]);
Console.WriteLine(builder.ToString());
Console.ReadKey(true);
source to share
but should be an effective solution
public StringBuilder Replace(this StringBuilder sb, string toReplace, Func<string> getReplacement)
{
for (int i = 0; i < sb.Length; i++)
{
bool replacementFound = true;
for (int toReplaceIndex = 0; toReplaceIndex < toReplace.Length; toReplaceIndex++)
{
int sbIndex = toReplaceIndex + i;
if (sbIndex < sb.Length)
{
return sb;
}
if (sb[sbIndex] != toReplace[toReplaceIndex])
{
replacementFound = false;
break;
}
}
if (replacementFound)
{
string replacement = getReplacement();
// reuse the space of the toReplace string
for (int replacementIndex = 0; replacementIndex < toReplace.Length && replacementIndex < replacement.Length; replacementIndex++)
{
int sbIndex = replacementIndex + i;
sb[sbIndex] = replacement[i];
}
// remove toReplace string remainders
if (replacement.Length < toReplace.Length)
{
sb.Remove(i + replacement.Length, replacement.Length - toReplace.Length)
}
// insert chars not yet inserted
if (replacement.Length > toReplace.Length)
{
sb.Insert(i + toReplace.Length, replacement.ToCharArray(toReplace.Length, toReplace.Length - replacement.Length));
}
}
}
return sb;
}
use case
var sb = new StringBuilder(script);
script = sb.Replace("@Unique", () => Guid.NewGuid().ToString()).ToString();
source to share