基本上我想做的是在单个字符串上运行多个 (15-25) 正则表达式替换,并尽可能进行最佳内存管理。
概述:
通过附加到 StringBuilder
的 ftp 传输纯文本文件(有时是 html)以获得非常大的字符串。文件大小从 300KB 到 30MB 不等。
正则表达式是半复杂的,但需要文件的多行(例如,识别一本书的章节),因此任意破坏字符串,或在每个下载循环中运行替换是不可能的。
示例替换:
Regex re = new Regex("<A.*?>Table of Contents</A>", RegexOptions.IgnoreCase);
source = re.Replace(source, "");
随着每次运行替换内存天空火箭,我知道这是因为字符串在 C# 中是不可变的,它需要制作一个副本 - 即使我调用 GC.Collect()
它仍然对一个 30MB 的文件帮助不够。
关于更好的方法或使用常量内存执行多个正则表达式替换的方法有什么建议(制作 2 个副本(因此内存中有 60MB),执行搜索,丢弃副本回到 30MB)?
更新:
似乎没有一个简单的答案,但对于 future 的人来说,我最终使用了以下所有答案的组合以使其达到可接受的状态:
如果可能,将字符串拆分成 block ,请参阅 manojlds 的回答以了解在读取文件时的方法 - 寻找合适的端点。
如果您不能在流式传输时拆分它,请至少在以后拆分它(如果可能的话)- 请参阅 ChrisWue 的一些外部工具的回答,这些工具可能有助于此过程以管道传输到文件。
优化正则表达式,避免贪婪运算符并尝试尽可能限制引擎必须执行的操作 - 请参阅 Sylverdrag 的回答。
尽可能合并正则表达式,这会减少正则表达式不基于彼此时的替换次数(在这种情况下有助于清理错误的输入)- 请参阅 Brian Reichle 的代码示例答案。
谢谢大家!
最佳答案
根据 RegEx 的性质,您可以将它们组合成一个正则表达式,并使用接受 MatchEvaluator 委托(delegate)的 Replace() 的重载来确定匹配字符串的替换。
Regex re = new Regex("First Pattern|Second Pattern|Super(Mega)*Delux", RegexOptions.IgnoreCase);
source = re.Replace(source, delegate(Match m)
{
string value = m.Value;
if(value.Equals("first pattern", StringComparison.OrdinalIgnoreCase)
{
return "1st";
}
else if(value.Equals("second pattern", StringComparison.OrdinalIgnoreCase)
{
return "2nd";
}
else
{
return "";
}
});
当然,如果后面的模式需要能够匹配较早替换的结果,这当然会分崩离析。
关于C# 多个正则表达式替换字符串 - 内存太多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5684311/