反向引用如何减慢正则表达式搜索的速度?

反向引用如何减慢正则表达式搜索的速度?

假设我有一个每行 20 个字符的文本文件,如下所示:

wertzuiopasdfghjkl<
asdfghjkl<yxcvbnm,.-
<yxcvbnm,.-123456789
1234567890QWERTZUIOP
QWERTZUIOPASDFGHJKL<

等等 ...

我希望这些行至少包含两个相同的字符,我可以grep这样使用

grep '\(.\).*\1' n20x1M

带有反向引用。在我的机器上,一百万行没有匹配需要 15.7 秒。

如果我将行数加倍,则所使用的 cpu 时间也会加倍,达到 31.4,正如预期的那样。

如果我有 28 列而不是 20 列(20 个字符给出 190 种可能的组合进行测试,28 个字符给出 378 种可能的组合),我还预计时间会加倍。但在我的机器上只有 28.2 秒。

那么反向引用的减慢不仅仅是通过纯粹的组合数量来测试的吗?我尝试过这个:

grep '^\(.\).*\1' n20x1M

这将组合数量从 190 个大幅减少到只有 19 个:只需读取第一个字符,看看它是否与其余字符匹配。这应该只需要 1.6 秒,但实际上需要 2.8 秒!

也许有一些将行读入内存和缓存的开销?不,如果我这样做

grep '.*_' n20x1M

处理时间仅为 0.004 秒!它主要做同样的事情(在 20 个字符的行中搜索一个字符),但是通过简单地不给出固定字符而是在剩余 19 个字符中搜索该行的第一个字符,我得到了超过因子的减速1000!

我的理解有错误吗?

反向引用引入了这么多隐藏开销吗?

或者 GNU 正则表达式中的反向引用实施得不好?

谁能解释一下这里发生了什么?

我可以做些什么来提高性能?

更新 @Sundeep 提到了关于缓慢反向引用的免责声明。但这是由于太多可能的解决方案而造成的计算结果。我预料到了这一点,但使用它们会带来额外的惩罚,即使它们不会增加复杂性。

这似乎确实是一个实现问题,正如他使用 option 的其他提示一样-P,我的加速从 15.4 秒到 2.0 秒!

带有锚点的简单情况^从 2.8 秒加速到 0.25 秒,但仍然无法满足搜索固定字符(0.004 秒)的要求。有趣的是,使用 option -P,固定字符情况会减慢至 0.13 秒,因此反向引用的惩罚较小,但更像是整体惩罚......

不幸的是,我既没有-P使用grepMacOS,也没有sed使用主要使用反向引用的任何版本。

相关内容