假设我想提取在某个文本文件中找到的给定字符串后面的第一个单词(或浮点数)(请参阅How to extract the first word that follows a string?)。我知道你可以使用perl或sed,以及其他许多方法。我正在寻找表现。什么是最快的解析方法?
答案 0 :(得分:3)
如果您正在寻找固定字符串,您可能希望使用Boyer-Moore或Boyer-Moore-Horspool之类的东西进行搜索(对于后者,我建议使用Ray Gardner的实现)。注意,B-M和B-M-H都是次线性。相反,正则表达式最多是线性的 1 ,并且许多实现(使用回溯的那些)是二次的。
下一步是确保您尽快将数据读入内存。实际上,这通常是瓶颈。不幸的是,为了妥善处理瓶颈,您通常必须使用一些不可移植的代码。在Linux下,mmap
往往是您最好的选择,而在Windows下,您通常通常一次只读取大块,并使用{{CreateFile
调用FILE_FLAG_NO_BUFFERING
1}}标志。使用I / O完成端口(IOCP)进行读取也是值得的,因此您可以并行执行搜索和读取。
1 从理论上讲,可以编写一个RE引擎,对正确的模式进行次线性搜索 - 但如果有任何实际的模式,我就不知道了。
答案 1 :(得分:1)
与大多数类似问题一样,我会实施您的特定案例并使用一系列适用工具进行衡量。
您可能发现其他因素会影响您的数字,例如打开/读取文件等的速度,因此技术建议毫无价值。
答案 2 :(得分:1)
大多数情况下,您将从磁盘读取字符串,或者更糟糕的是,从网络中读取字符串,这已经比您选择的任何理智的搜索方式慢了几个数量级。话虽如此,如果你的字符串已经在内存中,并且你事先知道你的搜索词,那么正则表达式(真正的基于FSM的,而不是Perl的)可以保证在时间上与输入大小成线性关系 - 所以更快的是只是通过一个恒定的因素更快。有一个名为re2的快速正则表达式引擎库。
答案 3 :(得分:0)
我敢打赌,如果它真的是一个简单的案例(没有真正的正则表达式),C会赢(memchr()和朋友),否则TCL将是一个强有力的竞争者,其次是Perl(后者需要良好的制作技巧正则表达式设计)。
附录:再次阅读您的说明(以及随附的链接),我会说您应该测试一些工具并比较结果。您能为我们(某处)提供输入文件并根据该文件指定确切的问题吗?
附录2(费曼): 我保存了这个网站(~44KB,'sof.dat')并进行了重复的搜索测试 (正如你在Perl中提出的那样:“网站设计/”)。这是使用的代码:
...
use Benchmark qw' timeit timestr ';
{
open my $fh, '<', 'sof.dat' or die $!;
undef $/;
our $data = <$fh>;
close $fh;
my $count = 100000;
my $t = timeit($count, ' $data =~ m|site design /| ? 1 : 0 ' );
print "$count loops of code took:", timestr($t),"\n";
}
...
通过我的设置(2,4GHz E6600,Win7,Activeperl),出现了以下时间:
100000个代码循环:1个挂钟秒 (1.36 usr + 0.00 sys = 1.36 CPU)@ 73746.31 / s(n = 100000)
这意味着,我可以在这个页面中找到每秒约74,000次的文本。
如果我包含完整的文件处理:
use Benchmark qw' timeit timestr ';
{
my $count = 10000;
my $t = timeit($count, q{
open my $fh, '<', 'sof.dat' or die $!;
undef $/;
our $data = <$fh>;
close $fh;
$data =~ m|site design /| ? 1 : 0
} );
print "$count loops of code took:", timestr($t),"\n";
}
我们只会得到:
10000个代码循环:3个wallclock secs(1.70 usr + 1.51 sys = 3.21 CPU)@ 3110.42 / s(n = 10000)
每秒约3千次搜索/查找通行证。
此致
RBO