正则表达式中的贪婪与否定字符类问题
我有一个很大的文件,看起来像这样(见下文)。我可以在它上使用正则表达式的两个基本选择(我知道可能还有其他选择,但我实际上是在尝试比较Greedy和Negated Char Class)方法。
ftp: [^\D]{1,} ftp: (\d)+ ftp: \d+
注意:如果我取消\ d周围的保护,该怎么办?
现在+是贪婪的,它会强制回溯,但是Negated Char Class需要逐字符比较。哪个更有效?假设文件非常大,由于文件的长度,处理器使用中的细微差别将被夸大。
既然我们已经回答了,如果我的否定字符类很大,说18个不同的字符怎么办?那会改变你的答案吗?
谢谢。
ftp: 1117 bytes ftp: 5696 bytes ftp: 3207 bytes ftp: 5696 bytes ftp: 7200 bytes
解决方案
这不是问题的直接答案,但是既然我们已经知道行的格式,为什么不完全采用另一种方法呢?例如,我们可以在字段之间的空白处使用正则表达式,或者完全避免在空白处使用正则表达式和split(),这通常比任何正则表达式都要快,具体取决于我们使用的语言。
[^ \ D] {1,}和\ d +完全相同。正则表达式解析器会将[^ \ D]和\ d编译为具有相同内容的字符类,并且+只是{1,}的缩写。
如果我们想懒惰重复,可以添加一个?在最后。
\d+?
字符类通常被编译为ASCII字符的位图。对于Unicode(> = 256),它取决于实现。一种方法是创建一个范围列表,并在其上使用二进制搜索。
对于ASCII,查找时间在整个大小上是恒定的。对于Unicode,它是对数或者线性的。
我的初始测试表明[^ \ D {1,}比\ d +慢一点,在184M文件上,前者需要9.6秒,而后者则需要8.2秒
不捕获(()),两者的速度都快约1秒,但是两者之间的差异大致相同。
我还进行了更广泛的测试,将捕获的值打印到/ dev / null,并在空间上拆分了第三个版本,结果:
([^\D]{1,}): ~18s (\d+): ~17s (split / /)[1]: ~17s
编辑:改进了拆分版本,减少了时间,使其等于或者小于(\ d +)
迄今为止最快的版本(有人可以改进吗?):
while (<>) { if ($foo = (split / /)[1]) { print $foo . "\n"; } }
这是一个技巧性的问题,因为由于捕获括号的开销,(\ d)+花费的时间稍长一些。如果将其更改为\ d +,则它们在我的perl /系统中花费的时间相同。
是的,我同意MizardX ...这两个表达式在语义上是等效的。尽管分组可能需要其他资源。那不是你要问的。
两个表情都具有相同的贪婪感。正如其他人在这里所说的,除了捕获组,它们将以相同的方式执行。
同样在这种情况下,贪婪对执行速度没有多大影响,因为\ d *之后没有任何内容。在这种情况下,表达式将只处理它可以找到的所有数字,并在遇到空格时停止。这些表达式不应发生回溯。
为了使它更明确,如果我们具有这样的表达式,则应进行回溯:
\d*123
在这种情况下,解析器将吞没所有数字,然后回溯以匹配后面的三个数字。