Perl 检测EOR与EOF时消除代码重复

Perl 检测EOR与EOF时消除代码重复,perl,loops,parsing,multiline,Perl,Loops,Parsing,Multiline,我正在循环多行记录并将它们加载到一个数组中。我碰巧在使用Perl,但语言与此无关,因为我正在寻找对算法的优化。具体地说,我为写两次数组推送而烦恼。当我找到记录结束(eor)时循环一次,当我用完文件时循环一次(eof,不是eor)。我知道这不会影响速度,我只是不想在两个地方重复代码。这意味着如果它改变了,我必须在两个地方进行修改 我采取的方法是: my $data = []; #data object array my $record = {}; my $line; while (my $line

我正在循环多行记录并将它们加载到一个数组中。我碰巧在使用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);
my$data=[]#数据对象数组
我的$record={};
我的美元线;
while(我的$line=){
如果($line=~/marker-a:(.*)/){
#更新数据对象
$$record{'a'}=$1;
}
如果($line=~/marker-b:(.*)/){
#更新数据对象
$$record{'b'}=$1;
}
如果($line=~/eor/){
#记录结束;添加到数据数组
推送(@$data,$record);
$record={};
}
}
#将剩余数据更新到数据数组
推送(@$data,$record);

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

因此,您希望在同一地点处理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;
    }
}
my$data=[];
我的$record={};
而(1){
我的$line=;
如果(!defined($line)| |$line=~/eor/){
按(@$data,$record)if键(%$record);
最后一个if!已定义($line);
$record={};
}
elsif($line=~/marker-a:(.*)/){
$record->{a}=$1;
}
elsif($line=~/marker-b:(.*)/){
$record->{b}=$1;
}
}

因此,您希望在同一位置处理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;
    }
}
my$data=[];
我的$record={};
而(1){
我的$line=;
如果(!defined($line)| |$line=~/eor/){
按(@$data,$record)if键(%$record);
最后一个if!已定义($line);
$record={};
}
elsif($line=~/marker-a:(.*)/){
$record->{a}=$1;
}
elsif($line=~/marker-b:(.*)/){
$record->{b}=$1;
}
}

所需的只是更改

if ( $line =~ /eor/ )

然后取下
按钮,将
推到环路外


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

my ($data, $record);

while ( <$file> ) {

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

    if ( ( /eor/ or eof ) and $record ) {
        push @$data, $record;
        $record = undef;
    }
}
my($data,$record);
而(){
如果(/marker-([ab]):(.*)/){
$record->{$1}=$2;
}
如果((/eor/或eof)和$record){
推送$数据,$记录;
$record=undf;
}
}

所需的只是更改

if ( $line =~ /eor/ )

然后取下
按钮,将
推到环路外


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

my ($data, $record);

while ( <$file> ) {

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

    if ( ( /eor/ or eof ) and $record ) {
        push @$data, $record;
        $record = undef;
    }
}
my($data,$record);
而(){
如果(/marker-([ab]):(.*)/){
$record->{$1}=$2;
}
如果((/eor/或eof)和$record){
推送$数据,$记录;
$record=undf;
}
}

我基本上不想采用复制粘贴的方法。如果EOR过程发生变化,我也必须改变EOF过程。我之所以这么问,是因为这似乎是一件必须反复出现的事情,我想知道其他人是如何处理这件事的。谢谢。我基本上不想用复制粘贴的方式。如果EOR过程发生变化,我也必须改变EOF过程。我之所以这么问,是因为这似乎是一件必须反复出现的事情,我想知道其他人是如何处理这件事的。谢谢。如果((…或eof),它将永远不会到达
因为循环将在此之前结束。也就是说,一旦它到达eof,循环就会中断,并且块不再被处理。这就是问题所在。然后,$record中缓存的数据不会推送到$data。不过,谢谢。@rfportilla,这不是真的。
eof
如果下次读取将返回eof,则返回真的。@rfportilla:很抱歉,在ikegami的回复引起我的注意之前,我忽略了您的评论。代码很好。
eof
将在从文件读取最后一行后的任何时间返回true,即在循环的最后一次迭代期间。它实际上执行
getc
,然后执行
ungect
,以检查t中是否有更多数据如果(…或eof),不消耗它的流将永远不会到达
if
因为循环将在此之前结束。也就是说,一旦它到达eof,循环就会中断,并且块不再被处理。这就是问题所在。然后,$record中缓存的数据不会推送到$data。不过,谢谢。@rfportilla,这不是真的。
eof
如果下次读取将返回eof,则返回真的。@rfportilla:很抱歉,在ikegami的回复引起我的注意之前,我忽略了您的评论。代码很好。
eof
将在从文件读取最后一行后的任何时间返回true,即在循环的最后一次迭代期间。它实际上执行
getc
,然后执行
ungect
,以检查t中是否有更多数据他在不使用它的情况下流。我知道这种方法;我只是不喜欢使用无限循环。:-(这似乎是一种方法。谢谢你的帮助!谢谢。我知道这种方法;我只是不喜欢使用无限循环。:-(这似乎是一种方法。谢谢你的帮助!