【问题标题】:I need a case-insensitive Replace method that works with the StringBuilder class我需要一个与 StringBuilder 类一起使用的不区分大小写的 Replace 方法
【发布时间】:2010-07-29 21:14:53
【问题描述】:

我需要 StringBuilder 类的不区分大小写的 Replace 方法的代码。该代码应与现有的StringBuilder 一起使用。扩展方法实现会很好。

以下是我打算如何使用该方法:

    [TestMethod]
    public void StringBuilder_Replace_TTD() {

        StringBuilder oRequestText = new StringBuilder(File.ReadAllText("Customer.xml"));

        Customer oCustomer = new Customer(null);

        foreach (FieldIndex iField in Enum.GetValues(typeof(FieldIndex))) {

            oRequestText.Replace("{" iField.ToString() + "}", oCustomer[iField]);

        }

        Debug.WriteLine(oRequestText.ToString());
    }

【问题讨论】:

  • 不区分大小写的替换如何准确工作? Foo 应该用 Bar 代替,FOO 应该用 BAR 代替吗?
  • @Mark:我认为替换中的“搜索”步骤不区分大小写。替换的值将是替换文本的任何内容。
  • 正确,我想用“BAR”替换“foo”,无论大小写。

标签: .net string replace stringbuilder case-insensitive


【解决方案1】:

StringBuilder 不支持在搜索/替换文本时使用IComparer(事实上,根本不支持搜索)。您可以尝试逐个字符滚动版本,但这会很复杂,并且可能仍然表现不佳。

根据您的用例,我建议使用字符串而不是StringBuilder,并使用string.IndexOf() 来定位输入字符串中您要进行替换的位置——这支持不区分大小写的搜索。找到所有替换区域后,创建一个StringBuilder,然后复制每个区域 - 将找到的文本替换为所需的替换值。

编辑:大概您希望使用 StringBuilder 替换来避免分配额外的字符串并因此而导致性能下降。然而,在StringBuilder 的缓冲区 替换文本实际上可能更昂贵 - 特别是如果替换字符串的长度与它们要替换的源字符串的长度不同。每次替换都需要根据替换文本是更短还是更长,将字符向前或向后移动。像这样执行内存块移动会很昂贵。

【讨论】:

  • 我有字符串的方法,但我想要 StringBuilder,因为我将进行 40 多个替换。我宁愿不创建 40 多个字符串。
  • @AMissico:我不建议你这样做。我建议您使用常规字符串 start 以利用不区分大小写的搜索方法。一旦找到要替换的所有子字符串的索引和长度,您可以选择性地从原始字符串复制到StringBuilder,并对找到的每个子字符串执行替换。它也比在 StringBuilder 中的替换更有效,因为它不需要 移动任何文本块,如果替换的长度与它们要替换的文本的长度不同,就会发生这种情况。
  • 我相信我明白你的建议。然而,我看不出如何避免创建 40+ 字符串来查找每个枚举成员的 索引和长度。性能不是我主要关心的问题。对于这种特定情况,我对干净的代码和生产就绪的代码更感兴趣。
  • @AMissico:如果您不关心性能,那么我对您的建议是保持简单。不要担心中间替换字符串 - 使用string.Replace()。任何涉及增量搜索和组合的解决方案(如使用 StringBuilder 时)都将比原始版本更复杂且更难维护。
  • 是的,这就是我现在正在做的事情,但我使用的是Microsoft.VisualBasic.Strings.Replace 而不是String.Replace。该功能速度极快,支持且不区分大小写。我想我只是在大声思考。
【解决方案2】:

发件人:http://blogs.msdn.com/b/btine/archive/2005/03/22/400667.aspx

string Replace( string expr, string find, string repl, bool bIgnoreCase )  
{
// Get input string length
       int exprLen = expr.Length;
       int findLen = find.Length;

       // Check inputs    
       if( 0 == exprLen || 0 == findLen || findLen > exprLen )    
              return expr;

       // Use the original method if the case is required    
       if( !bIgnoreCase )
              return expr.Replace( find, repl );

       StringBuilder sbRet = new StringBuilder( exprLen );

       int pos = 0;              
       while( pos + findLen <= exprLen )    
       {    
              if( 0 == string.Compare( expr, pos, find, 0, findLen, bIgnoreCase ) )    
              {    
                     // Add the replaced string    
                     sbRet.Append( repl );    
                     pos += findLen;    
                     continue;    
              }

              // Advance one character    
              sbRet.Append( expr, pos++, 1 );    
       }

       // Append remaining characters    
       sbRet.Append( expr, pos, exprLen-pos );

       // Return string    
       return sbRet.ToString();    
}

【讨论】:

  • 很遗憾没有测试用例......我很犹豫是否要对一段如此复杂的代码进行投票,而没有任何迹象表明它可以工作。此外,这似乎是 O(n^2)。例如,将IndexOfStringComparison.CurrentCultureIgnoreCase 一起使用不是更好吗?
  • 使用字符串并返回字符串。我想要一个与 StringBuilder 一起工作的方法,在替换期间不创建新字符串或新的字符串生成器。
  • @Mark - 它来自 MSDN,所以这意味着它必须 是正确的,对吧? :) @AMissico - 好的 - 现在我明白你的意思了......让我尝试一些事情。
  • @AMissico:“使用字符串并返回字符串”是的 - 这正是它应该的样子。 StringBuilder 是一个实现细节,不应该是方法接口的一部分。
  • +1 我对此进行了一些测试,它似乎至少可以正常工作,如果不是很快的话。
【解决方案3】:

在你想要做的例子中(在伪代码中):

StringBuilder oRequestText = ...;
For all fields do replace on oRequestText;
Debug.WriteLine(oRequestText.ToString());

由于在此之后您实际上并没有使用 StringBuilder,因此与

没有功能差异
StringBuilder oRequestText = ...;
string strRequest = oRequestText.ToString();
For all fields do replace on strRequest;
Debug.WriteLine(strRequest);

字符串的普通替换函数应该很容易支持你想要做的事情。

我假设在您的实际情况下您确实想再次使用 StringBuilder。但它可能仍然是最简单的 .ToString(),替换字符串,然后用字符串重新加载 StringBuilder。

【讨论】:

    【解决方案4】:

    我会使用 RegEx 替换方法,但这意味着从 StribgBuilder 转换为字符串

    oRequestText = new StringBuilder(Regex.Replace(oRequestText.ToString(), "{" iField.ToString() + "}", oCustomer[iField], RegexOptions.IgnoreCase)));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-30
      • 2014-10-23
      • 2016-03-29
      • 2013-10-08
      • 2022-01-22
      • 2012-01-31
      相关资源
      最近更新 更多