开发者

Mutable String Editing in C# / .NET

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜