正则表达式中贪婪与否定字符类的问题

时间:2008-10-03 19:34:33

标签: regex regex-greedy

我有一个非常大的文件,看起来像这样(见下文)。我有两个正则表达式的基本选择(我知道可能还有其他人,但我真的想比较Greedy和Negated Char Class)方法。

ftp: [^\D]{1,}
ftp: (\d)+
ftp: \d+

注意:如果我在\ d?

附近取下parense怎么办?

现在+贪婪迫使回溯,但Negated Char Class需要逐个字符比较。哪个更有效率?假设文件非常大,因此由于文件的长度,处理器使用的微小差异会被夸大。

既然你已经回答了这个问题,如果我的否定字母类很大,说18个不同的字符怎么办?这会改变你的答案吗?

感谢。

  

ftp:1117字节
      ftp:5696字节
  ftp:3207字节
    ftp:5696字节
  ftp:7200字节

6 个答案:

答案 0 :(得分:3)

[^ \ D] {1,}和\ d +完全相同。正则表达式解析器将[^ \ D]和\ d编译为具有相同内容的字符类,而+只是{1,}的缩写。

如果你想懒人重复你可以添加?最后。

\d+?

字符类通常编译为ASCII字符的位图。对于Unicode(> = 256),它取决于实现。一种方法是创建范围列表,并在其上使用二进制搜索。

对于ASCII,查找时间在大小上是恒定的。对于Unicode,它是对数或线性的。

答案 1 :(得分:2)

你的表情都有同样的贪婪。正如其他人在这里所说的,除了捕获组之外,它们将以相同的方式执行。

同样在这种情况下,贪婪在执行速度上并不重要,因为你在\ d *之后没有任何东西。在这种情况下,表达式将简单地处理它可以找到的所有数字,并在遇到空格时停止。这些表达式不会发生回溯。

为了使其更明确,如果您有这样的表达式,则应该进行回溯:

\d*123

在这种情况下,解析器将吞没所有数字,然后回溯以匹配后面的三个数字。

答案 2 :(得分:1)

我的初步测试显示[^ \ 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";
    }
}

答案 3 :(得分:1)

这是写的一个技巧问题,因为(\ d)+由于捕获括号的开销而需要稍长的时间。如果将其更改为\ d +,则在perl / system中花费相同的时间。

答案 4 :(得分:1)

是的,我同意MizardX ......这两个表达式在语义上是等价的。虽然分组可能需要额外的资源。那不是你要问的。

答案 5 :(得分:0)

不是问题的直接答案,但为什么不完全采用不同的方法,因为你已经知道线的格式了?例如,您可以在字段之间的空白处使用正则表达式,或者完全避免使用正则表达式和空白上的split(),这通常会比任何正则表达式更快,具体取决于您使用的语言。