【发布时间】:2014-03-21 08:06:08
【问题描述】:
首先我将解释我的程序试图解决的问题。我有两个输入文件,一个包含“好”数字行:
100000
100001
100002
100003
100004
另一个文件是一个“原始”数字文件,我想检查每一行,看看该行是否包含上面的“好”数字之一,后跟 4 个数字,另外 4 个数字可以是任何数字。所以如果包含原始数字的文件是:
8881000001234
1000014321
999991000021234567
00234100001
1000041234
100002123
1000029876
用正则表达式擦洗后,匹配的数字将是
1000001234
1000014321
1000021234
1000041234
1000029876
到目前为止,我这样做的方法是将“好的”数字存储在一个数组中,然后将“原始”数字转换成一个标量
my $FH
my@good_nums
open $FH, '<', 'good_numbers' or die $!;
while(<$FH>) { chomp; push @good_nums, $_; }
close $FH;
open $FH, '<', 'raw_numbers' or die $!;
my $raw_nums = do { local $/; <$FH> };
close $FH;
然后我可以做到这一点:
my @matches;
foreach my $num (@good_nums) {
push @matches, $raw_nums =~ /$num\d{4}/g;
}
所以@matches 包含正确的匹配项,并且运行良好。
但现在我已经开发了从不匹配的“原始”数字中捕获行的需要。我可以通过将“原始”数字放入一个数组(而不是吞下它们)并将join @good_nums 数组放入一个正则表达式来捕获不匹配的行:
my $QRnums = '(?:' . (join '|', @good_nums) . ')';
$QRnums = qr/$QRnums/;
my @raw_nums;
open my $FH, '<', 'raw_numbers' or die $!;
while(<$FH>) { chomp; push @raw_nums, $_; }
my @matches;
my @junk;
for (@raw_nums) {
if ($_ =~ /($QRnums\d{4})/g) {
push @matches, $1;
} else {
push @junk, $_;
}
}
这是可行的,但是当我将每个文件中的行数增加到 150,000 或更多时,后一种解决方案所需的时间是前一种解决方案的 4 或 5 倍。我知道必须有另一个 Perl 解决方案可以有效地解决我的问题,但我不知所措。我不太擅长中级 Perl 及更高版本。. 有没有更好的方法来做到这一点,或者我的第一个解决方案可以重写,以便我也可以获得数组中的非匹配项?除了需要解决我的帖子开头所解释的问题之外,我对任何事情都持开放态度。
【问题讨论】: