HiveBrain v1.2.0
Get Started
← Back to all entries
patternModerate

Perl 6 oneliner to sum up all numbers in a text file

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
fileallperlnumberstextsumoneliner

Problem

The task is to sum up scores mentioned in a text file. Scores are floating point numbers as defined by the regexp float immediately preceded by a * character to distinguish them from other numbers in the text. Scientific notation is not permitted.

Example input

Day 1:     
  Task 1: *5 Task 2: *2,8
  Task 3 was the hardest, your score is *-1
…


The expected sum here is 5 + 2.8 - 1 = 6.8.

my $sum = 0;

my regex float {
                 (?)          # opt. sign
                 (\d+)              # whole part
                 [()(\d*)]?   # opt. fractional part;
                                    #   comma is a valid separator
               }

for slurp.match( / \*  /, :g ) {
  my $f = $_;
  # justification for the next line:
  #  +"5," Cannot convert string to number: trailing characters after number
  #  +"5." Cannot convert string to number: radix point must be followed by one or more valid digits
  $sum += +"$f[1]$f[2].$f[4]0"
}

say $sum;


The code works, but it prints out a large number of warning messages

use of uninitialized value of type Any in string context


I would like to hear suggestions how to write this in a more idiomatic Perl.

In addition, I would like to hear how to make it more an one liner since I guess the code might be written with significantly less lines and still be readable.

Solution

The warning comes from the fact that the third and fourth capture groups are inside an optional part of the regex. Therefore, $f[4] might not be defined.

Rather than concatenating the parts of a decomposed number, I suggest taking all of $f[0] and replacing any comma with a period.

my $sum = 0;

my regex float {
                 ?          # opt. sign
                 \d+              # whole part
                 [  \d+ ]?  # opt. fractional part
                                      #comma is vaild separator
               }

for slurp.match( / \*  /, :g ) {
    $sum += +$_.subst( /','/ , '.' , :g );
}

say $sum;

Code Snippets

my $sum = 0;

my regex float {
                 <[+-]>?          # opt. sign
                 \d+              # whole part
                 [ <[.,]> \d+ ]?  # opt. fractional part
                                      #comma is vaild separator
               }

for slurp.match( / \* <float> /, :g ) {
    $sum += +$_<float>.subst( /','/ , '.' , :g );
}

say $sum;

Context

StackExchange Code Review Q#72123, answer score: 10

Revisions (0)

No revisions yet.