【问题标题】:Best way to replace tokens in a large text template在大型文本模板中替换标记的最佳方法
【发布时间】:2010-09-06 10:09:30
【问题描述】:

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

【问题讨论】:

    标签: c# .net


    【解决方案1】:

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

    Some kind soul did some performance testing,在 Regex.Replace()、String.Replace() 和 StringBuilder.Replace() 之间,实际上 String.Replace() 排在首位。

    【讨论】:

    • 我相信他们在不适用于 C# 的 PowerShell 中进行了测试。 C3 的内存管理与 PowerShell 不同,并且不会将 StringBuilder 转换为 String 以替换其中的字符。另一方面,RegEx 和 StringBuilder 在大数据量上效果更好,这些数据以块的形式添加到它们中
    • RegEx 是对大量文本执行替换的可怕选项。尽管它很强大,但许多 RegEx 支持者将整个世界视为钉子,将 RegEx 视为他们的锤子。对于涉及大量文本的用例,请查看 FastReplacer stackoverflow.com/a/11442008/141172
    【解决方案2】:

    我必须这样做的唯一情况是发送模板电子邮件。在 .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。我想你可以看看 MailDefinition.CreateMailMessage() with Reflector :)。抱歉有点跑题了,但如果这是你的场景,我认为这是最简单的方法。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

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

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

        【讨论】:

          【解决方案5】:

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

          【讨论】:

            【解决方案6】:

            正则表达式将是编码的最快解决方案,但如果您有许多不同的标记,那么它会变慢。如果性能不是问题,请使用此选项。

            更好的方法是定义标记,例如您可以在文本中扫描的“##”。然后从哈希表中选择要替换的内容,以标记后面的文本作为键。

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

            【讨论】:

              【解决方案7】:

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

              • 制作一个采用字典的方法(键 = 令牌名称,值 = 您需要插入的文本)
              • 使用 Regex.Matches(input, regular expression) 获取与您的标记格式匹配的所有匹配项(我猜你的情况是##.+?##,不是很擅长正则表达式 :P)
              • 遍历结果,使用字典查找令牌的插入值。
              • 返回结果。

              完成;-)

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

              【讨论】:

                【解决方案8】:

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

                FastReplacer 适用于在性能很重要时对大字符串执行许多替换操作。

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

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

                【讨论】:

                • 这就是我要找的。请查看速度表并试一试。
                【解决方案9】:

                如果您的模板很大并且有很多标记,您可能不想遍历它并一个一个替换模板中的标记,因为这会导致 O(N * M) 操作,其中 N 是模板的大小,M 是要替换的标记数。

                以下方法接受模板和您希望替换的键值对的字典。通过将 StringBuilder 初始化为略大于模板的大小,它应该会导致 O(N) 操作(即它不应该自己增长 log 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();
                }
                

                【讨论】:

                  【解决方案10】:

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

                  【讨论】:

                    猜你喜欢
                    • 2020-10-07
                    • 1970-01-01
                    • 2011-02-19
                    • 1970-01-01
                    • 2015-10-09
                    • 1970-01-01
                    • 2019-11-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多