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

时间:2008-08-21 15:36:25

标签: c# .net

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

10 个答案:

答案 0 :(得分:12)

System.Text.RegularExpressions.Regex.Replace()就是你所寻找的 - 如果你的代币很奇怪你需要一个正则表达式才能找到它们。

Some kind soul did some performance testing,在Regex.Replace(),String.Replace()和StringBuilder.Replace()之间,String.Replace()实际上名列前茅。

答案 1 :(得分:7)

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

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()。很抱歉有点偏离主题,但如果这是你的情景,我认为这是最简单的方法。

答案 2 :(得分:3)

嗯,取决于模板中有多少变量,有多少模板等,这可能是完整模板处理器的工作。我用过.NET的唯一一个是NVelocity,但我确信其中有很多其他的,其中大多数都链接到某个Web框架或其他框架。

答案 3 :(得分:2)

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

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

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

答案 4 :(得分:2)

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

答案 5 :(得分:2)

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

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

完成; - )

如果您想测试正则表达式,我可以建议the regulator.

答案 6 :(得分:2)

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

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

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

答案 7 :(得分:2)

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

  

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

     

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

     

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

答案 8 :(得分:1)

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

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

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

static string SimpleTemplate(string template, Dictionary<string, string> 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();
}

答案 9 :(得分:0)

这是正则表达式的理想用法。查看this helpful website.Net Regular Expressions class以及这本非常有用的书Mastering Regular Expressions

相关问题