Home > Enterprise >  Processing text file as blocks
Processing text file as blocks

Time:01-01

What is wrong with my code? My DATA has 4 blocks, but my code only prints result from first three blocks. The same result obtained when I read the data from a file.

#!/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

The result printed:

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

CodePudding user response:

The program prints the sum when it comes to an empty line but there is no extra line after the end of data. One way to fix that is to also test for end-of-file, with eof.

With the program slightly rearranged

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___
...

CodePudding user response:

You exit the loop when there's no data left, and you don't print anything after the loop.

Solution 1: Print something after the loop

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";
}

Solution 2: Don't exit the loop so soon.

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;
}

CodePudding user response:

Your code outputs only when you have a line with no data (there is no any validation for input data).

Sum of last data block will be printed out only if input data have last line with no data.

Study following sample code which is a slight modification of original code.

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

Output

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

There is a better way to make computation on input data of this kind.

use strict;
use warnings;
use feature 'say';

my(@blocks,$count,%sum);

@blocks = do { local $/ = "\n\n"; <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

Output

Sum of block 1: 823
Sum of block 2: 655
Sum of block 3: 6200
Sum of block 4: 1854
  •  Tags:  
  • perl
  • Related