StringBuilder ReplaceAt功能

时间:2012-08-06 15:27:37

标签: c# stringbuilder

我有一个我正在操作多次的字符串构建器,我需要用不同长度的字符串替换其中的字符串。

sb = new StringBuilder("This has {Count} Values.  Your search was '{SearchText}'.  Did you mean '{DidYouMean}'?")
//get the replacement areas, this would search for the field names within {}
MatchCollection matches = GetReplacementAreas(sb);

int indexOffset=0;
foreach(Match m in matches)
{
   //fields is a dictionary containing keys that match the fields
   sb.ReplaceAt(m.Index,m.Length,fields[m.Value]); 
}

显然,ReplaceAt不存在。我打算自己写。还有其他人已经这样做了吗?

2 个答案:

答案 0 :(得分:0)

public static class StringBuilderExtensions
{
#if EXTENSIONS_SUPPORTED
    public static StringBuilder ReplaceAt(this StringBuilder sb, string value, int index, int count)
    {
        return StringBuilderExtensions.ReplaceAt(sb, value, index, count);
    }
#endif

    public static StringBuilder ReplaceAt(StringBuilder sb, string value, int index, int count)
    {
        if (value == null)
        {
            sb.Remove(index, count);
        }
        else
        {
            int lengthOfValue = value.Length;

            if (lengthOfValue > count)
            {
                string valueToInsert = value.Substring(count);
                sb.Insert(index + count, valueToInsert);
            }
            if (lengthOfValue < count)
            {
                sb.Remove(index + count, lengthOfValue - count);
            }

            char[] valueChars = value.ToCharArray();
            for (int i = 0; i < lengthOfValue; i++)
            {
                sb[index + i] = valueChars[i];
            }
        }

        return sb;
    }
}

答案 1 :(得分:0)

出于准确性考虑,enorl76回答看起来很有希望,但不适用于Unicode字符串,尤其是宽度为2个字节的Unicode字符。这是.Net Fiddle中为考试准备的enorl76答案。

.Net Fiddle here是解决这个问题的一个实现。

using System.Linq;
using System.Diagnostics;
using System;
using System.Text;
using System.Globalization;

//Created for 
//http://metadataconsulting.blogspot.com/2019/03/A-Unicode-ReplaceAt-string-extension-method-handles-Unicode-string-properly.html

public static class Program
{


 const char cEMPTY = '\0'; 
    static readonly string EMPTY = cEMPTY.ToString(); 

    public static string UnicodeReplaceAt(this string str, int offset, char replaceChar)
    {
        int count = 1; //number of times to replace
        string replaceBy = replaceChar.ToString();
        return new StringInfo(str).ReplaceByPosition(replaceBy, offset, count).String;
    }

    public static StringInfo ReplaceByPosition(this StringInfo str, string replaceBy, int offset, int count)
    {
        if (replaceBy != EMPTY)
            return str.RemoveByTextElements(offset, count).InsertByTextElements(offset, replaceBy);
        else
            return str.RemoveByTextElements(offset, count);
    }

    public static StringInfo RemoveByTextElements(this StringInfo str, int offset, int count)
    { 
  //Tue 20-Aug-19 11:32am metadataconsulting.ca - replaceat index > string.len return orginal string
  if (offset > str.LengthInTextElements)
   return str;

        return new StringInfo(string.Concat(
            str.SubstringByTextElements(0, offset),
            offset + count < str.LengthInTextElements
                ? str.SubstringByTextElements(offset + count, str.LengthInTextElements - count - offset)
                : string.Empty
            ));
    }
    public static StringInfo InsertByTextElements(this StringInfo str, int offset, string insertStr)
    {
        //Tue 20-Aug-19 11:32am metadataconsulting.ca - replaceat index > string.len return orginal string
  if (offset > str.LengthInTextElements)
   return str;

  if (string.IsNullOrEmpty(str.String))
            return new StringInfo(insertStr);

        return new StringInfo(string.Concat(
            str.SubstringByTextElements(0, offset),
            insertStr,
            str.LengthInTextElements - offset > 0 ? str.SubstringByTextElements(offset, str.LengthInTextElements - offset) : ""
        ));
    }

    public static string SubsituteStringStringBuilder(this string s, int idx, char replaceChar)
    {
        if (string.IsNullOrEmpty(s) || idx >= s.Length || idx < 0)
            return s;

        return new StringBuilder(s).Remove(idx, 1).Insert(idx, replaceChar.ToString()).ToString();
    }

    public static string ReplaceAtSubstring(this string s, int idx, char replaceChar)
    {
        if (string.IsNullOrEmpty(s) || idx >= s.Length || idx < 0)
            return s;

        return s.Substring(0, idx) + replaceChar.ToString() + s.Substring(idx + replaceChar.ToString().Length, s.Length - (idx + replaceChar.ToString().Length));

    }

    public static string ReplaceAtStringManipulation(this string s, int idx, char replaceChar)
    {
        if (string.IsNullOrEmpty(s) || idx >= s.Length || idx < 0)
            return s;

        return s.Remove(idx, 1).Insert(idx, replaceChar.ToString());
    }

    public static string ReplaceAtLinq(this string value, int index, char newchar)
    {
        if (value.Length <= index)
            return value;
        else
            return string.Concat(value.Select((c, i) => i == index ? newchar : c));
    }

    public static string ReplaceAtCharArray(this string input, uint index, char newChar)
    {
        if (string.IsNullOrEmpty(input) || index >= input.Length)
            return input;

        char[] chars = input.ToCharArray();
        chars[index] = newChar;
        return new string(chars);
    }

    public static void Main()
    {
        //In .NET 4.5 and later also UTF-16 is supported
        //Console.OutputEncoding = System.Text.Encoding.Unicode;  

  //é  Latin Small Letter e with Acute U+00E9 - single byte Unicode character
  //? Smiling Face with Smiling Eyes Emoji U+1F60A - double byte Unicode character
  //? Multiple Musical Notes Emoji U+1F3B6 - - double byte Unicode character
  //? Fire Emoji U+1F525 -- double byte Unicode character

  Console.WriteLine("Unicode String Replace At Issue");
  Console.WriteLine("Lets examine string \"??é-\"");  
        Console.WriteLine("??é- is length of " + "??é-".Length + ", but there are ONLY 4 characters! Why not len=4?"); 
  Console.WriteLine("?? are double byte UNICODE characters (> \\u10000) of width or len 2 each ");
  Console.WriteLine("??é- below will replace space after lasting character '-' (position 4) with a sub using most common techniques seen online"); 

  Console.WriteLine(); 

  Stopwatch sw = new Stopwatch();
        sw.Start();
        Console.WriteLine("??é- using ReplaceAtCharArray".ReplaceAtCharArray(4, 'X'));
        sw.Stop();
        Console.WriteLine("in {0} ticks.", sw.ElapsedTicks.ToString("N0"));

        sw.Restart();
        Console.WriteLine("??é- using ReplaceAtLinq".ReplaceAtLinq(4, 'Y'));
        sw.Stop();
        Console.WriteLine("in {0} ticks.", sw.ElapsedTicks.ToString("N0"));

        sw.Restart();
        Console.WriteLine("??é- using ReplaceAtStringManipulation".ReplaceAtStringManipulation(4, 'Z'));
        sw.Stop();
        Console.WriteLine("in {0} ticks.", sw.ElapsedTicks.ToString("N0"));

        sw.Restart();
        Console.WriteLine("??é- using ReplaceAtSubstring".ReplaceAtSubstring(4, 'A'));
        sw.Stop();
        Console.WriteLine("in {0} ticks.", sw.ElapsedTicks.ToString("N0"));

        sw.Restart();
        Console.WriteLine("??é- using SubsituteStringStringBuilder".SubsituteStringStringBuilder(4, 'W'));
        sw.Stop();
        Console.WriteLine("in {0} ticks.", sw.ElapsedTicks.ToString("N0"));

  sw.Restart();
        Console.WriteLine("??é- using UnicodeReplaceAt".UnicodeReplaceAt(4, '4'));
        sw.Stop();
        Console.WriteLine("in {0} ticks.", sw.ElapsedTicks.ToString("N0"));

  Console.WriteLine(); 
  Console.WriteLine("UnicodeReplaceAt replaces properly at position 4 in zero based index string");
        Console.WriteLine(); 
  sw.Restart();
        Console.Write("??é- using UnicodeReplaceAt(0, '0')".UnicodeReplaceAt(0, '0'));
        sw.Stop();
  Console.WriteLine(" in {0} ticks.", sw.ElapsedTicks.ToString("N0"));
  sw.Restart();
        Console.Write("??é- using UnicodeReplaceAt(1, '1')".UnicodeReplaceAt(1, '1'));
        sw.Stop();
  Console.WriteLine(" in {0} ticks.", sw.ElapsedTicks.ToString("N0"));
  sw.Restart();
        Console.Write("??é- using UnicodeReplaceAt(2, '2')".UnicodeReplaceAt(2, '2'));
        sw.Stop();
  Console.WriteLine(" in {0} ticks.", sw.ElapsedTicks.ToString("N0"));
  sw.Restart();
        Console.Write("??é- using UnicodeReplaceAt(3, '3')".UnicodeReplaceAt(3, '3'));
        sw.Stop();
  Console.WriteLine(" in {0} ticks.", sw.ElapsedTicks.ToString("N0"));
  sw.Restart();
        Console.Write("??é- using UnicodeReplaceAt(4, '4')".UnicodeReplaceAt(4, '4'));
        sw.Stop();
        Console.WriteLine(" in {0} ticks.", sw.ElapsedTicks.ToString("N0"));
     Console.Write("??é-".UnicodeReplaceAt(5, '5')+" using UnicodeReplaceAt(5, '5') - this is beyond end of string, so return orginal string");
        sw.Stop();
        Console.WriteLine(" in {0} ticks.", sw.ElapsedTicks.ToString("N0"));



  Console.WriteLine(); 
  Console.WriteLine("String.Replace works, but replaces all characters, not at specific location as above functions");
        Console.WriteLine(); 
  Console.Write("??é- using String.Replace".Replace("?", "+") + "('?', '+')");


    }
}