我在文件<$IN>
上进行迭代,逐行处理。我希望根据分割字段中保存的值跳过一些行,我目前通过以下方式完成:
while (<$IN>) {
chomp $_;
my(@F) = split("\t", $_);
next if ($F[0] == 1 && $F[1] > 20 && $F[1] < 40);
但是我有多个这样的行和标准要检查。我更愿意加载包含测试值的.txt文件,例如:
1 20 40
1 63 68
2 1 10
2 12 18
3 3 9
找到一种较短的方法来测试任何给定的线对这些范围,而不需要像我现在那样需要很多线:
next if ($F[0] == 1 && $F[1] > 20 && $F[1] < 40);
next if ($F[0] == 1 && $F[1] > 63 && $F[1] < 68);
next if ($F[0] == 2 && $F[1] > 1 && $F[1] < 10);
next if ($F[0] == 2 && $F[1] > 12 && $F[1] < 18);
next if ($F[0] == 3 && $F[1] > 3 && $F[1] < 9);
有人能提供一个如何以更简洁的方式做到这一点的例子吗?
答案 0 :(得分:3)
将范围存储在数据结构中,例如
#!/usr/bin/perl
use warnings;
use strict;
my %skip = ( 1 => [ [20, 40], [63, 68] ],
2 => [ [ 1, 10], [12, 18] ],
3 => [ [ 3, 9] ]
);
while (<>) {
my @F = split;
next if grep $F[1] >= $_->[0] && $F[1] <= $_->[1],
@{ $skip{ $F[0] } };
print;
}
答案 1 :(得分:3)
您可以毫无问题地将该配置外包到文件中。我会使用散列(ref)作为列号,使用数组ref作为最小值和最大值,如下所示。由于每个字段可以有多对值,因此需要一个数组数组。
use strict;
use warnings;
use Data::Printer;
# open my $fh, '<', 'config.txt' or die $!;
my $config;
while (my $line = <DATA>) {
chomp $line;
my ( $col, $min, $max )= split /\s+/, $line;
push @{ $config->{$col} }, [ $min, $max ];
}
p $config;
__DATA__
1 20 40
1 63 68
2 1 10
2 12 18
3 3 9
数据结构如下所示:
\ {
1 [
[0] [
[0] 20,
[1] 40
],
[1] [
[0] 63,
[1] 68
]
],
2 [
[0] [
[0] 1,
[1] 10
],
[1] [
[0] 12,
[1] 18
]
],
3 [
[0] [
[0] 3,
[1] 9
]
]
}
哈希使得exists
可以很容易地检查字段哈希值是否完整。然后你可以像这样使用它。
use strict;
use warnings;
# see the code example above
my $config = {
1 => [ [ 20, 40 ], [ 63, 68 ] ],
2 => [ [ 1, 10 ], [ 12, 18 ] ],
3 => [ [ 3, 9 ] ],
};
sub skip_line {
my @F = @_;
return unless exists $config->{$F[0]}; # nothing to skip in this field
foreach my $pair (@{ $config->{$F[0]} }) {
return 1 if $F[1] > $pair->[0] && $F[1] < $pair->[1];
}
}
while (<DATA>) {
chomp;
my @F = split /\s+/; # \t
next if skip_line(@F);
print; # output unskipped lines
}
__DATA__
1 21 30
2 19 20
您当然可以使用较短的表单而不是skip_line
函数,如choroba's answer所示。