I want to take and edit a string in-place in a .NET app. I know that StringBuilder
allows me to do in-place appends, inserts, and replaces, but it does not allow an easy way of doing stuff like this:
while (script.IndexOf("@Unique", StringComparison.InvariantCultureIgnor开发者_如何转开发eCase) != -1)
{
int Location = script.IndexOf("@Unique", StringComparison.InvariantCultureIgnoreCase);
script = script.Remove(Location, 7);
script = script.Insert(Location, Guid.NewGuid().ToString());
}
As there is no IndexOf
in StringBuilder
. Does anyone have an effective way to do in-place editing of textual information?
Edit #1: Changed sample to make more obvious that each 'replace' needs to have a different result.
If your code really is this straightforward then why not just use one of the built-in Replace
methods, either on string
, StringBuilder
or Regex
?
EDIT FOLLOWING COMMENT...
You can replace each occurrence with a separate value by using one of the overloads of Regex.Replace
that takes a MatchEvaluator
argument:
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));
How many replacements will you be doing?
If its not four figures, then just accept the new string instances, you may be prematurely optimising...
Another solution... Split on "@uniqueID" then rejoin with a StringBuilder adding your seperator for each iteration.
How about StringBuilder
"Replace" method:
StringBuilder script;
script.Replace("@Unique", GetGuidString());
StringBuilder is made so that you can easily add to it, but at the tradeoff that it's difficult to search in it - and especially, it's more difficult (i.e. slower) to index it. If you need to modify some characters "in-place", it's best to do it on the resulting string.
But it's difficult to know from your question what is the right answer for you, my feeling is that you shouldn't be needing in-place replacement in a StringBuilder, and the problem is somewhere else/you do something else wrong.
User Dennis has provided an IndexOf extension method for StringBuilder. With this, you should be able to use StringBuilder in this manner.
Can you use a string split 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);
complex but should be performant 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();
You are going to need to use an unmanaged code block As simple as declare a pointer to your string and manipulate it in memory.
Example
unsafe
{
char* ip;
ip = &to_your_string;
}
精彩评论