我何时应该使用已编译的正则表达式进行解释?

时间:2009-01-06 04:38:28

标签: .net regex

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

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

<小时/> 嗨,谢谢你的答案,我的实际代码不是直截了当的,并且在动态构建的RE中受到了损害,所以我不能包含它,所以对于所有密集的目的,这里有一个例子来说明我的方法:

foreach (field field in fields.Where(x => x.condition))
    MatchResults = Regex.Match(request.Message, field.RegularExpression);
...

4 个答案:

答案 0 :(得分:12)

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

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

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

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

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

只有在处理了如此多的数据时,才应该使用RegexOptions.Compiled,用户实际上必须等待正则表达式。如果您无法使用秒表测量速度差异,请不要使用RegexOptions.Compiled。

答案 1 :(得分:2)

当必须使用RE超过两次或三次时,我会编译RE,并且编译的成本会被结果执行时间的改进所抵消。

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

编辑:你提到的那篇文章指出,前期编译比解释慢一个数量级(十次),因此只能节省30%。此外,无论如何,解释的RE都被缓存。所以我会说这肯定是在反对随意使用编译。

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

答案 2 :(得分:0)

听起来我对你的表达过于具体。我有兴趣看到你正在尝试解析的代码示例,因为我的直觉告诉我你的方法可能不够通用。如果情况并非如此,例如,在循环期间比较的每个表达式也可以预先编译。

请修改您的问题并添加一些代码,以便我们为您提供进一步的帮助。

答案 3 :(得分:0)

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

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