Perl 检测EOR与EOF时消除代码重复
我正在循环多行记录并将它们加载到一个数组中。我碰巧在使用Perl,但语言与此无关,因为我正在寻找对算法的优化。具体地说,我为写两次数组推送而烦恼。当我找到记录结束(eor)时循环一次,当我用完文件时循环一次(eof,不是eor)。我知道这不会影响速度,我只是不想在两个地方重复代码。这意味着如果它改变了,我必须在两个地方进行修改 我采取的方法是: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
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中是否有更多数据他在不使用它的情况下流。我知道这种方法;我只是不喜欢使用无限循环。:-(这似乎是一种方法。谢谢你的帮助!谢谢。我知道这种方法;我只是不喜欢使用无限循环。:-(这似乎是一种方法。谢谢你的帮助!