【问题标题】:When should I use a compiled Regex vs. interpreted?我什么时候应该使用已编译的正则表达式与解释?
【发布时间】:2009-01-06 04:38:27
【问题描述】:

阅读本文http://www.codinghorror.com/blog/archives/000228.html 后,我更了解编译正则表达式的好处,但是在哪些个人情况下您会考虑强制使用编译正则表达式?

例如,我在循环中使用正则表达式,并且正则表达式字符串每次迭代使用不同的变量,所以我不会通过将此正则表达式标记为已编译来寻求改进吗?


嗨,感谢您的回答,我的实际代码并不简单,并且受到动态构建的 RE 的影响,因此我无法包含它,因此出于所有密集目的,这里有一个示例来演示我的方法:
foreach (field field in fields.Where(x => x.condition))
    MatchResults = Regex.Match(request.Message, field.RegularExpression);
...

【问题讨论】:

    标签: .net regex


    【解决方案1】:

    在 .NET 中,有两种“编译”正则表达式的方法。正则表达式在用于查找匹配项之前总是被“编译”。当您在没有 RegexOptions.Compiled 标志的情况下实例化 Regex 类时,您的正则表达式仍会转换为 Regex 类使用的内部数据结构。实际的匹配过程在该数据结构上运行,而不是代表您的正则表达式的字符串。只要您的 Regex 实例存在,它就会一直存在。

    如果您多次使用同一个正则表达式,则显式实例化 Regex 类比调用静态 Regex 方法更可取。原因是静态方法无论如何都会创建一个 Regex 实例,然后将其丢弃。它们确实保留了最近编译的正则表达式的缓存,但缓存相当小,而且缓存查找的成本远高于简单地引用指向现有正则表达式实例的指针。

    上述编译形式存在于每一种使用正则表达式的编程语言或库中,但并非所有都提供对它的控制。

    .NET 框架通过构造 Regex 对象并指定 RegexOptions.Compiled 标志来提供编译正则表达式的第二种方法。此标志的缺失或存在并不表示正则表达式是否已编译。它指示正则表达式是如上所述快速编译,还是如下所述彻底编译。

    RegexOptions.Compiled 真正做的是创建一个新程序集,将您的正则表达式编译为 MSIL。然后这个程序集被加载,编译成机器代码,并成为应用程序的永久部分(当它运行时)。这个过程会占用大量的 CPU ticks,并且内存使用是永久性的。

    仅当您使用 RegexOptions.Compiled 处理大量数据以致用户实际上必须等待您的正则表达式时,才应使用 RegexOptions.Compiled。如果您无法使用秒表测量速度差异,请不要使用 RegexOptions.Compiled。

    【讨论】:

      【解决方案2】:

      当 RE 的使用次数超过 2 或 3 次并且编译成本被结果执行时间的改进所抵消时,我会编译它。

      我从不编译一次性 RE,我总是编译那些执行次数超过五次(给予或接受几次)但我从未发现需要参数化 RE(可能存在这种需要,只是我'从来没有找到它)所以它不会进入它。

      编辑:您提到的那篇文章指出,预先编译比解释(十倍)慢一个数量级,但仅节省 30%。而且,此外,解释的 RE 无论如何都会被缓存。所以我会说这绝对是在反对随意使用编译。

      节省 30% 意味着需要 100/3(约 33)次编译的 RE 执行才能恢复编译的初始成本。这是根据 .NET 上的 MSDN 文档 - 我一直认为在我的 RE(Python/Perl/Java)中它不会那么糟糕,但我想我应该检查一下。

      【讨论】:

      • 我的问题是,我的正则表达式可能被执行了数百次,但是匹配字符串不断地被轻微改变。
      • 如果匹配字符串是指 RE 的输入,编译还是更好。如果您的意思是对 RE 本身进行更改,那么您每次都在有效地编译 RE,所以不要打扰。
      • 没错,就是改变 RE 本身。我就是这么想的,我不应该打扰。
      • 查看编辑:我绝对不会以数量级的成本。
      • 非常有趣 - 尤其是执行大约 33 次才能收回成本。
      【解决方案3】:

      在我看来,你的表达方式过于具体。我有兴趣查看您实际尝试解析的代码示例,因为我的直觉告诉我您的方法可能不够通用。如果不是这种情况,例如,也可以在循环期间预编译一组表达式并进行比较。

      请编辑您的问题并添加一些代码,以便我们进一步帮助您。

      【讨论】:

        【解决方案4】:

        只有当正则表达式足够复杂时,才应该编译正则表达式。简单的正则表达式将在未编译的情况下更有效地执行,因为编译时间会不必要地增加开销。如果您的正则表达式非常复杂但只使用一次,那么您应该评估它是否会从编译中受益。您可以通过设置一个对两个备选方案计时的例程来衡量这一点。

        在几乎所有多次使用正则表达式的情况下,都值得在循环外编译正则表达式。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-05-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多