简体   繁体   中英

Perl, how to only add numbers in each row of a file

I have a text file, looking similar to this:

1 Bob J Smith 3 4 2 1 10 8
2 James Miller 5 3 82 3 44 1
3 ...

What I'm trying to achieve is to only add the numbers in each row and give total per person. But has to skip past the first number (that is before the name) and text and only compute numbers. My @lines array holds the file I need to work with.

my $total;
my @row;
foreach(@lines){
        @row=split;
        $total=0;
        $total+=$_ for @row[3..$#row];
        print "$row[0]: $total\n";
}
print "$row[0]: $total\n";

Reading a file into an array and then iterating over the array isn't generally an improvement over just iterating over the file. You shouldn't read the whole file into memory unless you particularly need to for some reason like requiring random access to the data

Your data format isn't very usable unless you actually have tabs separating the name from the surrounding fields. Otherwise there is no way to distinguish parts of the name from the rest of the fields

This program works by repeatedly adding together the last two fields of each line until the last field but one isn't numeric. It assumes the last field of every line is always numeric and doesn't make any checks for this

use strict;
use warnings 'all';

while ( <DATA> ) {

    my @fields = split;

    while ( $fields[-2] =~ /\A\d+\z/ ) {
        push @fields, pop(@fields) + pop(@fields);
    }

    print "@fields\n";
}

__DATA__
1 Bob J Smith 3 4 2 1 10 8
2 James Miller 5 3 82 3 44 1

output

1 Bob J Smith 28
2 James Miller 138

Or use regular expressions to divide each line into name and numbers and then total the numbers.

while (<DATA>)
{  
    chomp;
    next if /^$/;
    my $total = 0;
    /\d+ ([A-Za-z ]+) ([\s\d]+)$/;
    my @numbers = split(' ', $2);
    $total += $_ for (@numbers);
    print "$1: $total\n";
}

__DATA__
1 Bob J Smith 3 4 2 1 10 8
2 James Miller 5 3 82 3 44 1
3 Allan X Smith 5 4 82 3 44 2

Possibly simpler and more straight forward:

use strict;
use warnings;

use List::Util 'sum';

while ( <DATA> ) {
    my @row = split;

    print shift @row, ' '; # print row number

    while (@row and $row[0] !~ /^\d+$/) { # print name
        print shift @row, ' ';
    }

    print sum(@row, 0), $/;
}

__DATA__
1 Bob J Smith 3 4 2 1 10 8
2 James Miller 5 3 82 3 44 1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM