将文本文件作为块处理

  • 本文关键字:处理 文本 文件 perl
  • 更新时间 :
  • 英文 :


我的代码有什么问题?我的DATA有4个块,但我的代码只打印前三个块的结果。从文件中读取数据得到的结果是一样的。

#!/usr/bin/perl
use 5.30.3;
use warnings;
my $sum=0;
my $block=1;
while(<DATA>){
chomp(my $line = $_);
if ($line !~ /^$/){
$sum = $sum+$line;
}else{
say "Sum of block-${block}: $sum";
$sum = 0;
$block++;
}
}
__DATA__
345
478
300
255
100
1200
1000
4000
182
347
611
714

打印结果:

Sum of block-1: 823
Sum of block-2: 655
Sum of block-3: 6200

程序在遇到空行但数据结束后没有额外行时打印总和。解决这个问题的一种方法是使用eof.

测试文件结束符。程序稍微重新排列

use strict;
use warnings;
use feature 'say';
my $sum = 0;
my $block = 0;
while (my $line = <DATA>) {
chomp $line;
if ($line =~ /^$/ or eof DATA){
++$block;
say "Sum of block-$block: $sum";
$sum = 0;
} else {
$sum += $line;
}
}
say "Read $block blocks";
__DATA___
...

当没有剩余数据时退出循环,并且在循环结束后不打印任何内容。

解决方案1:在循环

后打印一些内容
while ( my $line = <DATA> ) {
chomp( $line );
if ( $line =~ /^$/ ) {
if ( defined( $sum ) ) {
say "Sum of block-${block}: $sum";
$sum = undef;
++$block;
}
next;
}
$sum += $line;
}
if ( defined( $sum ) ) {
say "Sum of block-${block}: $sum";
}

解决方案2:不要这么快退出循环。

while ( 1 ) {
my $line = <DATA>;
if ( !defined( $line ) || $line =~ /^$/ ) {
if ( defined( $sum ) ) {
say "Sum of block-${block}: $sum";
$sum = undef;
++$block;
}
if ( defined( $line ) ) {
next;
} else {
last;
}
}
chomp( $line );
$sum += $line;
}

只有当一行没有数据时(对输入数据没有任何验证),代码才会输出。

只有当输入数据的最后一行没有数据时,才会输出最后一个数据块的和。

学习下面的示例代码,这是对原始代码的轻微修改。

use strict;
use warnings;
use feature 'say';
my $sum=0;
my $block=1;
while( <DATA> ) {
chomp;
$sum += $1 if /(d+)/;
if( /^s*$/ && $sum ) {
say "Sum of block-${block}: $sum";
$sum = 0;
$block++;
}
}
say "Sum of block-${block}: $sum" if $sum;
exit 0;
__DATA__
345
478
300
255
100
1200
1000
4000
182
347
611
714

输出
Sum of block-1: 823
Sum of block-2: 655
Sum of block-3: 6200
Sum of block-4: 1854

有一种更好的方法来对这类输入数据进行计算。

use strict;
use warnings;
use feature 'say';
my(@blocks,$count,%sum);
@blocks = do { local $/ = "nn"; <DATA> };
for my $block ( @blocks ) {
++$count;
$sum{$count} += $_ for $block =~ /(d+)/gsm;
}
say "Sum of block $_: $sum{$_}" for sort keys %sum;
exit 0;
__DATA__
345
478
300
255
100
1200
1000
4000
182
347
611
714

输出
Sum of block 1: 823
Sum of block 2: 655
Sum of block 3: 6200
Sum of block 4: 1854

最新更新