Regex 哪个正则表达式性能更好?
我想用一个通用前缀(/files)来匹配URL,但在它下面只有两个特定的目录——图像和视频。我可以为此想出两个正则表达式:Regex 哪个正则表达式性能更好?,regex,Regex,我想用一个通用前缀(/files)来匹配URL,但在它下面只有两个特定的目录——图像和视频。我可以为此想出两个正则表达式: ^/files/(?:image|video)s/ /files/(图像/*|视频/*) 及 /files/(image | video)s/* 我这里有两个问题: 从性能角度看,哪一个更好?我的猜测是第二个,因为它的DFA将拥有较少的州 是否有一种通用编程语言,其内置的正则表达式编译器会将给定的正则表达式简化为最小的DFA 性能对我很重要,因为我将使用它来匹配数十亿个字
^/files/(?:image|video)s/
/files/(图像/*|视频/*)
及
/files/(image | video)s/*
我这里有两个问题:
import timeit
once = 'import re; m="/files/images/test"'
num = 1000000
print timeit.timeit(stmt='re.findall(r"/files/(images/.*|videos/.*)", m)', setup=once, number=num)
-> 1.5884420871734619
print timeit.timeit(stmt='re.findall(r"/files/(image|video)s/.*", m)', setup=once, number=num)
-> 1.5990869998931885
这将使用regex 100万次,并且在运行两条线多次后,两条线的速度都相同
Python可能会缓存已编译的正则表达式
我试了一下
- /文件/图像/测试
- /文件/视频/测试
- /文件/视频/测试
/files/(images/*| videos/*)
)在我的测试中运行快了一点(0.1秒)我的直觉(我知道不是太有用)会说第二个选项更好。但是考虑一下:
- 为什么要添加
*
- 能否将正则表达式锚定到行的开头
- 你需要捕获该组吗
^/files/(?:image|video)s/
从性能角度看,哪一个更好?我的猜测是第二个,因为它的DFA将拥有较少的州
这两个表达式在最小DFA中具有相同数量的状态,并且它们的DFA匹配相同的“语言”(理论意义上)
无论DFA中的状态数是多少,性能在理论上都是相同的,因为在将输入提供给自动机时,您将确定地遍历这些状态
在实践中,由于缓存未命中,可能会有差异,当存在更多状态时,这种情况可能会更频繁地发生。然而,除非你在使用正则表达式引擎,否则我想不出有什么好的理由花时间进行黑盒优化
是否有一种通用编程语言,其内置的正则表达式编译器会将给定的正则表达式简化为最小的DFA
Go()和Haskell拥有将regex转换为DFA的引擎。不过,我不知道DFA是否最小
由于POSIX ERE不支持反向引用(反向引用与替换中捕获组的引用不同),因此可以为POSIX ERE编写一个在DFA或高效NFA模拟上运行的引擎。但是,由于只要结果是正确的(匹配最左边最长的字符串),该标准就不强制执行该实现,因此该实现可以在NFA回溯引擎上彻底搜索与正则表达式匹配的所有字符串
但是,至少GNU EGRP(基于文件名dfa.c
)
请参考以下信息:
- DFA
- NFA仿真算法
- NFA回溯
- 对于(理论)正则表达式,存在具有子匹配跟踪(捕获组)的有效NFA仿真算法
- 为什么回溯引擎如此突出(例如Java、Python、Perl2等)
2:Perl实现了一个带有记忆的回溯引擎 - 回溯引擎在输入长度上可能需要指数时间,而汤普森的NFA模拟算法需要O(mn)时间,其中m是正则表达式的长度,n是输入的长度
- 目前已知的将(ir)正则表达式与反向引用匹配的最有效算法是回溯方法。因此,一些引擎决定不支持反向参考以提高匹配效率
- 回溯引擎(即使有记忆)比汤普森的NFA模拟算法慢
顺便说一下,re2引擎(如上所述)包括基于DFA和基于NFA(高效模拟)匹配算法的实现。感谢您的测试用例!你知道为什么第一个跑得更快吗?python internall是否将其减少到最小DFA?我无法控制此表达式的使用位置。他们要求。*在场。正则表达式不需要锚定到行的开头)。而且我不需要抓捕这群人。我不知道这是如何回答我的问题的:)你可以把这些澄清作为评论来问。答案是“我的直觉告诉我第二个更好”。当然,其余的可能是一个评论。:)@NHAHDH-感谢您提到这一点。我知道其中的区别和事实。我只提到了DFA,因为NFA至少在理论上等同于某些DFA。