组合正则表达式的算法复杂度

时间:2015-11-22 23:06:46

标签: regex time-complexity

一位同事和我正在讨论正则表达式的复杂性。

如果字符串以“.XX”结尾,我有 n 正则表达式匹配。例如:

regex 1 matches if the string ends in .AAA
regex 2 matches if the string ends in .BB
regex 3 matches if the string ends in .C
etc. (n times)

假设输入字符串与上述任何正则表达式匹配,我想编写一个返回true的函数。
我可以对 n 正则表达式进行循环,并在regexp匹配时立即返回true;在这种情况下,复杂性在正则表达式的 n 中是线性的。

另一种方法是创建一个大的正则表达式:

regex A matches if the string ends in .AAA or in .BB or in .C (etc n times)

这次我有一个正则表达式。

从复杂的角度来看,第二种方法是否更好?我认为检查此正则表达式的时间在 n 中仍然是线性的。但是,我的同事说这个正则表达式在 n 方面具有不变的复杂性。他的观点是,一旦编译了大正则表达式,就会产生一个用 n 标签生成的巨大开关,并且交换机上的分支是在恒定时间内完成的(即,不管有多少个案例,开关)。

那么,哪个答案是正确的?

1 个答案:

答案 0 :(得分:4)

对于交替组的每个级别,当您使用替换时,大多数正则表达式引擎会创建 trie

我想象它并没有使用类似语句的开关,更像是链接的 节点列表。

例如,如果这些都是字母,则每个字母都有一个人工插槽。所以无论你有多少单词,在字母的基础上,每个单词只有一个(在那个级别)。

" .AAA或.BB或.C"会产生一个正则表达式\.(?:AAA|BB|C)$;失败时最多只有4次比较。

我不认为使用了switch语句。

此外,每次输入新的正则表达式时都会进行初始化 开销罚款(不大,但可以加起来)。因此,最好使用一个使用trie的正则表达式,然后定期重新输入它。

与往常一样,如果添加,您可以轻松找到匹配的匹配项 捕获组\.(?:(AAA)|(BB)|(C))$。匹配后,一个简单的布尔值 通过匹配器进行的标志检查会告诉您哪一个匹配。

修改
为了清楚一些事情,一些引擎在它出现时会自动生成一个正则表达式 遇到交替小组,有些人没有。

Trie's基于有序节点树结构,指向下一个节点和子节点。每个节点可以指向另一个排序列表。

root
   |
   a --------- e ----- r
   |           |       |
   m --- n     m       o
   |     |     |       |
   y     n     m       b ----- g
   |     |     |       |       |
  \0    \0     a      \0       e
               |               |
              \0               r
                               |
                              \0

我认为引擎可能会实现一个叫做三元树的更快版本 不确定。

有关性能的参考,请看一下这个正则表达式 ASCII 175,000_word Mix A-Z Multi Lined
这是一本175,000字的字典。

这个正则表达式是一个完全实现的字典trie,具有
查找每个单词的路径不超过7条 尽管它的大小,它的速度非常快。

它是使用RegexFormat 7 Ternry Tree 工具生成的 为了测试它,或者只是为了使用正则表达式来解决这个问题 抓住试用版并下载字典样本 打开样本并加载其附加的正则表达式(从工具栏中),
单击测试窗口并再次按F3。