Regex Perl:尝试加快解析分隔文件的速度
我有一个大的平面文本文件,其中的行包含名称/值对(“varname=value”)。这些对由多字符分隔符分隔。因此,此文件中的一行可能如下所示:Regex Perl:尝试加快解析分隔文件的速度,regex,perl,split,Regex,Perl,Split,我有一个大的平面文本文件,其中的行包含名称/值对(“varname=value”)。这些对由多字符分隔符分隔。因此,此文件中的一行可能如下所示: var1=value1|^|var2=value2|^|var3=value3|^|var4=value4 每行包含大约50个名称/值对 我需要遍历这个文件的行(大约有100000行)并将名称/值对存储在散列中,以便 $field{'var1'}=value1 $field{'var2'}=value2 等 我所做的是: #$line保存文件中的一
var1=value1|^|var2=value2|^|var3=value3|^|var4=value4
每行包含大约50个名称/值对
我需要遍历这个文件的行(大约有100000行)并将名称/值对存储在散列中,以便
$field{'var1'}=value1
$field{'var2'}=value2
等
我所做的是:
#$line保存文件中的一行
my@fields=split(/\Q^^\E/,$line);
foreach my$字段(@fields){
我的($name,$value)=拆分(/=/,$field);
$hash{$name}=$value;
}
对整个文件的每一行执行此操作(在我的电脑上)大约需要2秒钟。这似乎不是很长时间,但我真的想加快一点
在这2秒钟中,第一次拆分大约需要0.6秒,而foreach循环大约需要1.4秒。所以我想我应该去掉foreach循环,把它全部放在一个单独的分割中:
%hash=split(/\Q |^\E |=/,$line);
令我惊讶的是,以这种方式解析整个文件花费了整整一秒钟的时间!我的问题不是为什么这需要更长的时间(尽管理解为什么会是一个很好的奖励),但我的问题是是否有其他(更快的)方法来完成这项工作
提前谢谢
----编辑此行下方---
我刚刚发现改变这一点:
%hash=split(/\Q |^\E |=/,$line);
为此:
$line=~s/\Q^\E/=/g;
%散列=拆分(/=/,$line);
使它快三倍!以这种方式解析整个文件现在只需一秒钟
----这一行下面的片段---
使用严格;
使用时间:雇佣qw(时间);
我的$line="“a=1124四四四四四方方在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场在场12月14日,q=17124四四四四四四方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方方aj=36 ^ ak=37 ^ al=38 ^ am=39 ^ an=40 ^ ao=41 ^ ap=42 ^ aq=43 ^ ar=44 ^ as=45|^|aw=49 | ^ | ax=50”;
重置计时器();
我的%hash;
对于(我的$i=1;$i我无法轻松回答您的性能问题,因为我需要一个测试用例。但我想这与正则表达式的处理方式有关
您可以看到使用re'debug';
执行的操作,这将打印正则表达式步骤
但对于更广泛的问题,我可能会用一个全局的方法来解决它(假设您的数据与示例一样简单):
这将“强制”将输入拆分成新行,然后匹配“anything”=“anything”。但这可能太过分了,除非您的值包括空格/管道/元字符
通过编辑测试用例以使用基准测试
:
#!/usr/bin/env perl
use strict;
use warnings;
use Benchmark qw ( cmpthese );
my $line =
"a=1|^|b=2|^|c=3|^|d=4|^|e=5|^|f=6|^|g=7|^|h=8|^|i=9|^|j=10|^|k=11|^|l=12|^|m=13|^|n=14|^|o=15|^|p=16|^|q=17|^|r=18|^|s=19|^|t=20|^|u=21|^|v=22|^|w=23|^|x=24|^|y=25|^|z=26|^|aa=27|^|ab=28|^|ac=29|^|ad=30|^|ae=31|^|af=32|^|ag=33|^|ah=34|^|ai=35|^|aj=36|^|ak=37|^|al=38|^|am=39|^|an=40|^|ao=41|^|ap=42|^|aq=43|^|ar=44|^|as=45|^|at=46|^|au=47|^|av=48|^|aw=49|^|ax=50";
sub double_split {
my %hash;
my @fields = split( /\Q|^|\E/, $line );
foreach my $field (@fields) {
my ( $name, $value ) = split( /=/, $field );
$hash{$name} = $value;
}
}
sub single_split {
my %hash = split( /\Q|^|\E|=/, $line );
}
sub re_replace_then_split {
$line =~ s/\Q|^|\E/=/g;
my %hash = split( /=/, $line );
}
sub single_regex {
my %hash = $line =~ m/(\w+)=(\w+)/g;
}
sub compound {
my %hash = $line =~ s/\Q|^|\E/\n/rg =~ m/(.*)=(.*)/g;
}
cmpthese(
1_000_000,
{ "Double Split" => \&double_split,
"single split with regex" => \&single_split,
"Replace then split" => \&re_replace_then_split,
"Single Regex" => \&single_regex,
"regex to linefeed them match" => \&compound
}
);
看起来结果是这样的:
Rate Double Split single split with regex Single Regex Replace then split regex to linefeed them match
Double Split 18325/s -- -4% -34% -56% -97%
single split with regex 19050/s 4% -- -31% -54% -97%
Single Regex 27607/s 51% 45% -- -34% -96%
Replace then split 41733/s 128% 119% 51% -- -93%
regex to linefeed them match 641026/s 3398% 3265% 2222% 1436% --
…我对最后一个有点怀疑,因为它的速度快得离谱。可能有结果缓存发生在那里
但是看看它,让你慢下来的是正则表达式中的交替:
sub single_split_with_alt {
my %hash = split( /\Q|^|\E|=/, $line );
}
sub single_split {
my %hash = split( /[\|\^\=]+/, $line );
}
(我知道后者可能不是你想要的,但只是为了说明)
给出:
Rate alternation single split
alternation 19135/s -- -37%
single split 30239/s 58% --
但确实有一点是没有意义的,因为您的限制因素是磁盘IO,而不是CPU。更多的示例数据可能会有所帮助。或者是一个可运行的代码段。我在上面添加了一个可运行的代码段。:)提供了一个带有一些比较测试的示例。(例如,使用基准测试
)如果你真的需要额外的速度,你可能需要考虑写。“因为你的限制因素是磁盘IO,而不是CPU。”可能不是。在我的旧系统中,一个慢的SSD,在每行100000行文件的每行中读取一个CHOMP文件需要0.7秒。实际上是这组中最慢的,但在您的示例中速度最快,因为它与一个已经更改的$行(在re_replace_then_split()中更改了它)。很好地发现了。我认为有一个原因如此之快,但没有深入挖掘。(重新运行我的测试而不包括replace then split给出了更合理的数字)
sub single_split_with_alt {
my %hash = split( /\Q|^|\E|=/, $line );
}
sub single_split {
my %hash = split( /[\|\^\=]+/, $line );
}
Rate alternation single split
alternation 19135/s -- -37%
single split 30239/s 58% --