一位同事和我正在讨论正则表达式的复杂性。
如果字符串以“.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 标签生成的巨大开关,并且交换机上的分支是在恒定时间内完成的(即,不管有多少个案例,开关)。
那么,哪个答案是正确的?
答案 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。