2008-08-21 33 views
13

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

回答

12

System.Text.RegularExpressions.Regex.Replace()是你所寻求的 - 如果你的令牌足够奇怪,你需要一个正则表达式来找到它们。

Some kind soul did some performance testing以及Regex.Replace(),String.Replace()和StringBuilder.Replace()之间,String.Replace()实际上排在最前面。

+1

我相信他们在PowerShell中做了不适用于C#的测试。 C3与PowerShell有不同的内存管理,并且不会将StringBuilder转换为字符串来替换它中的字符。另一方面,正则表达式和StringBuilder在大块数据上更好地工作 – AaA 2013-04-24 07:38:49

+0

RegEx是对大量文本进行替换的可怕选项。尽管功能强大,许多RegEx支持者将整个世界视为钉子和RegEx作为他们的锤子。对于涉及大量文本的用例,请看FastReplacer http://stackoverflow.com/a/11442008/141172 – 2014-11-05 17:57:05

2

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

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

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

2

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

2

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

  • 做,需要一个字典的方法(键=标记名称,值=你需要插入文本)
  • 获取所有你的令牌格式(##场比赛+#? #在你的情况下,我猜想,在正则表达式中不是那么好:P)使用Regex.Matches(输入,正则表达式)
  • foreach结果,使用字典为你的标记查找插入值。
  • 返回结果。

做;-)

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

7

我不得不这样做的唯一情况是发送一个模板化的电子邮件。在.NET中,开箱即用MailDefinition class提供。因此,这是你如何创建一个模板消息:

MailDefinition md = new MailDefinition(); 
md.BodyFileName = pathToTemplate; 
md.From = "[email protected]"; 

ListDictionary replacements = new ListDictionary(); 
replacements.Add("<%To%>", someValue); 
// continue adding replacements 

MailMessage msg = md.CreateMailMessage("[email protected]", replacements, this); 

在此之后,msg.Body将通过模板替换值创建。我想你可以看看MailDefinition.CreateMailMessage()与反射器:)。对不起,有点偏离主题,但如果这是你的情况,我认为这是最简单的方法。

2

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

更好的方法是定义令牌,就像您可以在文本中扫描的“##”一样。然后选择要使用以令牌作为关键字的文本从散列表中替换的内容。

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

3

那么,取决于你在模板中有多少变量,你有多少模板等,这可能是一个完整的模板处理器的工作。我曾经用过.NET的唯一一个是NVelocity,但我确定其中必须有其他许多人,其中大部分都与某些Web框架或其他框架相关联。

1

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

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

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

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(); 
} 
2

FastReplacer实现为O令牌替换(N *的log(n)+ m)个时间,并使用3倍原始字符串的存储器中。

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

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

我们设计了FastReplacer来帮助我们完成一个项目,在这个项目中,我们必须生成一个大量文本,并附加大量的附加和替换操作。使用StringBuilder生成文本的第一个版本的应用程序需要20秒。使用String类的第二个改进版本花了10秒钟。然后我们实现了FastReplacer,持续时间缩短到0.1秒。

相关问题