在大型文本模板中替换令牌的最佳方法

我有一个大文本模板,需要将标记化的部分替换为其他文本。 令牌看起来像这样:## USERNAME ##。 我的第一直觉只是使用String.Replace(),但是有更好,更有效的方法还是已经为此优化的Replace()?

你正在寻找System.Text.RegularExpressions.Regex.Replace() – 如果你的令牌很奇怪,你需要一个正则表达式才能找到它们。

某种灵魂进行了一些性能测试 ,在Regex.Replace(),String.Replace()和StringBuilder.Replace()之间,String.Replace()实际上名列前茅。

我必须这样做的唯一情况是发送模板化的电子邮件。 在.NET中, MailDefinition类提供了开箱即用的function 。 这就是你创建模板化消息的方式:

MailDefinition md = new MailDefinition(); md.BodyFileName = pathToTemplate; md.From = "test@somedomain.com"; ListDictionary replacements = new ListDictionary(); replacements.Add("<%To%>", someValue); // continue adding replacements MailMessage msg = md.CreateMailMessage("test@someotherdomain.com", replacements, this); 

在此之后,将通过替换模板中的值来创建msg.Body。 我猜你可以看看带有Reflector :)的MailDefinition.CreateMailMessage()。 很抱歉有点偏离主题,但如果这是你的情景,我认为这是最简单的方法。

好吧,根据模板中有多少变量,你有多少模板等,这可能是一个完整模板处理器的工作。 我曾经用过.NET的唯一一个是NVelocity ,但我确信那里必须有很多其他的,其中大多数都与某个Web框架或其他框架相关联。

string.Replace很好。 我更喜欢使用正则表达式,但我是正则表达式的***。

要记住的是这些模板有多大。 如果它真的很大,并且内存是个问题,您可能想要创建一个作用于流的自定义标记生成器。 这样,在操作它时,您只能将文件的一小部分保存在内存中。

但是,对于naiive实现,string.Replace应该没问题。

如果你在大字符串上进行多次替换,那么使用StringBuilder.Replace()可能会更好,因为字符串的常见性能问题会出现。

正则表达式是最快的代码解决方案,但如果你有许多不同的令牌,那么它会变慢。 如果性能不是问题,那么使用此选项。

更好的方法是定义令牌,就像您可以在文本中扫描的“##”一样。 然后从哈希表中选择要替换的内容,并将令牌后面的文本作为键。

如果这是构建脚本的一部分,那么nAnt有一个很棒的function,称为Filter Chains 。 这个代码是开源的,所以你可以看看它是如何快速实现的。

最近不得不做类似的事情。 我做的是:

  • 创建一个带字典的方法(key = token name,value =你需要插入的文本)
  • 使用Regex.Matches(输入,正则表达式)获取所有匹配到您的令牌格式(##。+?##在您的情况下我猜,不是那么擅长正则表达式:P)
  • 预测结果,使用字典查找令牌的插入值。
  • 返回结果。

完成;-)

如果你想测试你的正则表达式我可以建议监管机构。

FastReplacer在O(n * log(n)+ m)时间内实现令牌替换,并使用原始字符串的3倍内存。

当性能很重要时,FastReplacer适用于对大字符串执行许多Replace操作。

主要思想是避免每次更换字符串时修改现有文本或分配新内存。

我们设计了FastReplacer来帮助我们完成一个项目,我们必须生成一个包含大量追加和替换操作的大文本。 应用程序的第一个版本花了20秒使用StringBuilder生成文本。 使用String类的第二个改进版本耗时10秒。 然后我们实现了FastReplacer,持续时间降至0.1秒。

这是正则表达式的理想用法。 查看这个有用的网站 , .Net正则表达式课程 ,以及这本非常有用的书籍掌握正则表达式 。

如果你的模板很大并且你有很多令牌,你可能不想走它并逐个替换模板中的令牌,因为这将导致O(N * M)操作,其中N是大小的template和M是要替换的标记数。

以下方法接受您要替换的键值对的模板和字典。 通过将StringBuilder初始化为略大于模板的大小,它应该导致O(N)操作(即它不应该自己增长N次)。

最后,您可以将令牌的构建移动到Singleton中,因为它只需要生成一次。

 static string SimpleTemplate(string template, Dictionary replacements) { // parse the message into an array of tokens Regex regex = new Regex("(##[^#]+##)"); string[] tokens = regex.Split(template); // the new message from the tokens var sb = new StringBuilder((int)((double)template.Length * 1.1)); foreach (string token in tokens) sb.Append(replacements.ContainsKey(token) ? replacements[token] : token); return sb.ToString(); }