StringBuilder中的正则表达式替换
我正在将文本文件的内容写入StringBuilder,然后我想使用正则表达式对StringBuilder中包含的文本执行许多查找/替换操作。
我遇到了一个问题,因为StringBuilder替换函数不能接受正则表达式参数。
我可以在普通字符串上使用Regex.Replace,但我认为这是低效的,因为需要在内存中创建字符串的两个副本,因为.net字符串是不可变的。
一旦我更新了文本,我打算将其写回原始文件。
什么是解决我问题的最佳和最有效的方法?
编辑
除了下面的答案,我发现以下问题也解释了我的问题 –
- 内存效率和性能的字符串替换净框架
- IS-StringBuilder的替换,更高效的超字符串替换
- 在乜点,确实-使用-A-的StringBuilder-成为无意义,或-的开销
您最好和最有效的解决方案是首先尝试最简单的方法:忘记StringBuilder
并使用Regex.Replace
。 然后找出它有多慢 – 它可能已经足够好了。 不要忘记在编译和非编译模式下尝试正则表达式。
如果这还不够快,可以考虑使用StringBuilder
进行简单表达的任何替换,然后再使用Regex.Replace
。 您可能还想考虑尝试组合替换,减少使用的正则表达式(以及因此中间字符串)的数量。
你有3个选择:
-
像其他人在这里推荐的那样,使用字符串以低效的方式执行此操作。
-
在
Regex
对象上使用.Matches()
调用,并模拟.Replace()
工作方式(参见#3)。 -
调整
Regex
的Mono实现来构建一个接受StringBuilder
的Regex
(请在这里分享!)几乎所有的工作都已经在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); }