StringBuilder中的正则表达式替换

我正在将文本文件的内容写入StringBuilder,然后我想使用正则表达式对StringBuilder中包含的文本执行许多查找/替换操作。

我遇到了一个问题,因为StringBuilder替换函数不能接受正则表达式参数。

我可以在普通字符串上使用Regex.Replace,但我认为这是低效的,因为需要在内存中创建字符串的两个副本,因为.net字符串是不可变的。

一旦我更新了文本,我打算将其写回原始文件。

什么是解决我问题的最佳和最有效的方法?

编辑

除了下面的答案,我发现以下问题也解释了我的问题 –

  • 内存效率和性能的字符串替换净框架
  • IS-StringBuilder的替换,更高效的超字符串替换
  • 在乜点,确实-使用-A-的StringBuilder-成为无意义,或-的开销

您最好和最有效的解决方案是首先尝试最简单的方法:忘记StringBuilder并使用Regex.Replace 。 然后找出它有多慢 – 它可能已经足够好了。 不要忘记在编译和非编译模式下尝试正则表达式。

如果这还不够快,可以考虑使用StringBuilder进行简单表达的任何替换,然后再使用Regex.Replace 。 您可能还想考虑尝试组合替换,减少使用的正则表达式(以及因此中间字符串)的数量。

你有3个选择:

  1. 像其他人在这里推荐的那样,使用字符串以低效的方式执行此操作。

  2. Regex对象上使用.Matches()调用,并模拟.Replace()工作方式(参见#3)。

  3. 调整Regex的Mono实现来构建一个接受StringBuilderRegex (请在这里分享!)几乎所有的工作都已经在Mono中为你完成了,但是需要时间来完成使它工作的部分。自己的图书馆 奇怪的是,Mono的正则Regex利用了Novell 2002年JVM实现的Regex

在单声道:

System.Text.RegularExpressions.Regex使用RxCompiler以RxInterpreterFactory的forms实例化RxInterpreterFactory ,这毫不奇怪地使IMachine成为RxInterpreter 。 获得那些排放是你需要做的大部分工作,尽管如果你只是想了解它是如何为效率而设计的,那么你所寻找的很多东西都在它的基类BaseMachine

特别是在BaseMachine是基于StringBuilder的东西。 在方法LTRReplace ,它首先使用初始字符串实例化StringBuilder,并且从那里开始的所有内容都是纯粹基于StringBuilder的。 如果我们假设内部Microsoft .Net实现类似,那么Regex没有挂起StringBuilder方法实际上非常烦人。

回到建议2,您可以通过调用.Matches() ,跟踪您在原始字符串中的位置以及循环来模仿LTRReplace的行为:

 var matches = regex.Matches(original); var sb = new StringBuilder(original.Length); int pos = 0; // position in original string foreach(var match in matches) { sb.Append(original.Substring(pos, match.Index)); // Append the portion of the original we skipped pos = match.Index; // Make any operations you like on the match result, like your own custom Replace, or even run another Regex pos += match.Value.Length; } sb.Append(original.Substring(pos, original.Length - 1)); 

但是,这只能为你节省一些字符串 – mod-Mono方法是唯一真正做到正确的方法。

我不确定这是否有助于你的场景,但我遇到了一些内存消耗上限和Regex,我需要在StringBuilder上使用一个简单的通配符替换扩展方法来推动它。 如果你需要复杂的正则表达式匹配和/或反向引用,这是不行的,但如果简单*或? 通配符替换(使用文字“替换”文本)将为您完成工作,然后在我的问题结束时的解决方法至少应该给你一个提升:

是否有人围绕StringBuilders或Streams实现了正则表达式和/或Xml解析器?

这是一种可以用来完成你想要的扩展方法。 它接受一个Dictionary ,其中键是您正在寻找的模式,值是您想要替换它的值。 您仍然可以创建传入字符串的副本,但您只需处理一次,而不是为Regex.Replace多次调用创建副本。

 public static StringBuilder BulkReplace(this StringBuilder source, IDictionary replacementMap) { if (source.Length == 0 || replacementMap.Count == 0) { return source; } string replaced = Regex.Replace(source.ToString(), String.Join("|", replacementMap.Keys.Select(Regex.Escape).ToArray()), m => replacementMap[m.Value], RegexOptions.IgnoreCase); return source.Clear().Append(replaced); }