编辑 2:对于为什么这仍然很重要的实际演示,只需看看stackoverflow 自己的正则表达式导致的中断今天(2016-07-20)!
编辑:自从我第一次提出这个问题以来,这个问题已经有了很大的发展。请参阅下面的两个快速+兼容但不完全功能的实现。如果您知道更多或更好的实现,请提及它们,这里还没有理想的实现!
我在哪里可以找到可靠快速的正则表达式实现?
有谁知道.NET或本机的正常非回溯(回溯)线性时间正则表达式实现,并且可以从.NET合理使用?System.Text.RegularExpressions
为了有用,它需要:
- 正则表达式评估的最坏情况时间复杂度为O ( m*n),其中 m 是正则表达式的长度,n 是输入的长度。
- 具有O(n) 的正常时间复杂度,因为几乎没有正则表达式实际上触发指数状态空间,或者,如果可以,仅在输入的一分钟子集上这样做。
- 具有合理的构建速度(即没有潜在的指数 DFA)
- 旨在供人类使用,而不是数学家 - 例如,我不想重新实现 unicode 字符类: .NET 或 PCRE 样式字符类是一个加号。
奖励积分:
- 如果它实现了基于堆栈的功能,可以让它以消耗 O(n+m) 内存而不是 O(m) 内存为代价来处理嵌套,那么它的实用性就会得到加分。
- 捕获子表达式或替换的奖励积分(如果有可能的子表达式匹配的指数数量,那么枚举所有它们本质上是指数的 - 但枚举前几个不应该是,替换也是如此)。您可以通过使用另一个功能来解决缺少任何一个功能的问题,因此拥有一个就足够了。
- 将正则表达式视为第一类值的很多奖励积分(因此您可以采用并集、交集、连接、否定 - 特别是否定和交集,因为这些很难通过正则表达式定义的字符串操作来实现)
- 惰性匹配,即在无限流上匹配而不将其全部放入内存是一个优点。如果流不支持查找,则(通常)不可能一次捕获子表达式和/或替换。
- 反向引用已经过时了,它们根本不可靠;即在给定病态输入案例的情况下,总是可以表现出指数行为。
存在这样的算法(这是基本的自动机理论......) - 但是是否有任何可从 .NET 访问的实际可用的实现?
背景:(可以跳过)
我喜欢使用正则表达式进行快速而肮脏的文本清理,但我反复遇到 perl/java/python/.NET 使用的常见回溯 NFA 实现显示指数行为的问题。不幸的是,一旦您开始自动生成正则表达式,这些情况就很容易触发。当您在匹配相同前缀的正则表达式之间交替使用时,即使是非指数性能也会变得非常差 - 例如,在一个非常基本的示例中,如果您将字典转换为正则表达式,预计性能会很糟糕。
要快速了解为什么存在以及自 60 年代以来存在更好的实现,请参阅正则表达式匹配可以简单快速。
不太实用的选择:
- 几乎是理想的:FSA 工具包。可以将正则表达式编译为 DFA + NFA 的快速 C 实现,也允许转换器(!),具有一流的正则表达式(封装耶!),包括交集和参数化的语法。 但它在序言中......(为什么具有这种实用功能的东西在主流语言中不可用???)
- 快速但不切实际:完整的解析器,例如优秀的ANTLR ,通常支持可靠的快速正则表达式。但是,antlr 的语法要冗长得多,并且当然允许可能无法生成有效解析器的构造,因此您需要找到一些安全的子集。
好的实现:
- RE2 - 一个谷歌开源库,旨在实现合理的 PCRE 兼容性减去反向引用。我认为这是作者给出的 plan9 正则表达式库的 unix 端口的继承者。
- TRE - 也主要与 PCRE 兼容,甚至可以进行反向引用,尽管使用那些你会失去速度保证。并且它有一个超级漂亮的近似匹配模式!
不幸的是,这两种实现都是 C++,并且需要从 .NET 使用互操作。