在检测EOR与EOF时删除代码重复

时间:2015-06-22 18:22:56

标签: perl loops parsing multiline

我循环遍历多行记录并将它们加载到数组中。我碰巧使用Perl,但语言无关紧要,因为我正在寻找算法的优化。具体来说,我对两次编写数组的事实感到困扰。一旦进入循环,当我找到记录结束(eor)时,再次当我用完文件时(eof,而不是eor)。我知道这不影响速度,我只是不喜欢在两个地方重复代码。这意味着如果它发生变化,我必须在两个地方进行修改。

我采取的方法是:

my $data = []; #data object array
my $record = {};
my $line;
while (my $line = <$file>){
    if($line =~ /marker-a:(.*)/){
        # Update data object
        $$record{'a'} = $1;
    }
    if($line =~ /marker-b:(.*)/){
        # Update data object
        $$record{'b'} = $1;
    }
    if($line =~ /eor/){
        # End of record; add to data array
        push(@$data,$record);
        $record = {};
    }
}
#Update leftover data to data array
push(@$data,$record);

有更好的方法吗?我知道我可以创建一个函数,但我正在寻找更优雅的东西。我还没有测试过这段代码,但它应该足以让我知道我在做什么。如果有任何问题,请告诉我。

2 个答案:

答案 0 :(得分:3)

所以你想要在同一个地方处理EOR和EOF。这意味着检查EOF不再能够在循环的顶部完成。将条件移入循环的技巧是切换到无限循环。

my $data = [];
my $record = {};
while (1) {
    my $line = <$file>;
    if (!defined($line) || $line =~ /eor/) {
        push(@$data, $record) if keys(%$record);
        last if !defined($line);
        $record = {};
    }
    elsif ($line =~ /marker-a:(.*)/) {
        $record->{a} = $1;
    }
    elsif ($line =~ /marker-b:(.*)/) {
        $record->{b} = $1;
    }
}

答案 1 :(得分:2)

所有必要的是改变

if ( $line =~ /eor/ )

if ( $line =~ /eor/ or eof )

并删除循环外的push

更新

这是一个更完整的解决方案,它使用最佳实践并避免将空记录推送到阵列

my ($data, $record);

while ( <$file> ) {

    if ( /marker-([ab]):(.*)/ ) {
        $record->{$1} = $2;
    }

    if ( ( /eor/ or eof ) and $record ) {
        push @$data, $record;
        $record = undef;
    }
}