Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Remove letters from variables used in math operation?

by shadowfox (Sexton)
on Dec 08, 2012 at 21:09 UTC ( #1007926=perlquestion: print w/ replies, xml ) Need Help??
shadowfox has asked for the wisdom of the Perl Monks concerning the following question:

I have variables used in math operations that have some extra non-digit data, usually just a letter following them. The math works fine, but naturally I get warnings about the argument not being numeric.
use warnings; while ($line = <DATA>){ chop($line); ($a,$b,$c,$d,$e,$f,$g)=split(",",$line); $sum = ($a+$b+$c+$d+$e+$f+$g); print $sum; } __END__ 86f,934e,92,102i,14,19,222,
The value at the end, 1469 is accurate but I'd like to take out the letters and avoid the warnings as they are not needed in my data context.
Argument "934e" isn't numeric in addition (+) at test.pl line 7, <DATA +> line 1. Argument "86f" isn't numeric in addition (+) at test.pl line 7, <DATA> + line 1. Argument "102i" isn't numeric in addition (+) at test.pl line 7, <DATA +> line 1. 1469
I tried using (s/\D//g) in various ways but I'm just getting it wrong, can this be easily done without altering each variable before the math operation individually? Please don't lecture me on strictures, this is a small example of my problem, not polished code.

Comment on Remove letters from variables used in math operation?
Select or Download Code
Re: Remove letters from variables used in math operation?
by tobyink (Abbot) on Dec 08, 2012 at 21:17 UTC

    Easy peasy!

    use warnings; while ($line = <DATA>){ chop($line); ($a,$b,$c,$d,$e,$f,$g)=split(",",$line); no warnings qw(numeric); $sum = ($a+$b+$c+$d+$e+$f+$g); print $sum; } __END__ 86f,934e,92,102i,14,19,222,

    The numeric warning is not compulsory; it's not even enabled by default (hence you needing to explicitly type use warnings). If it's not helping you, then turn it off.

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

      While switching off warnings is OK when you are sure of the format of your data, be aware of subtle pitfalls. In particular, scientific notation. For example:

      '934e' + 1; # value is 935 '934e0' + 1; # ok, value is still 935 '934e3' + 1; # oops, value is 934001 (scientific notation)

Re: Remove letters from variables used in math operation?
by AnomalousMonk (Abbot) on Dec 08, 2012 at 21:22 UTC

    Another peasibility:

    >perl -wMstrict -le "my $s = '86f,934e,92,102i,14,19,222,'; ;; my ($a,$b,$c,$d,$e,$f,$g) = split m{ [[:alpha:]]* , }xms, $s; my $sum = ($a+$b+$c+$d+$e+$f+$g); ;; print $sum; " 1469

    Update: Or even:

    >perl -wMstrict -le "use List::Util qw(sum); ;; my $s = '86f,934e,92,102i,14,19,222,'; ;; my $sum = sum split m{ [[:alpha:]]* , }xms, $s; ;; print $sum; " 1469

    Also (tested):  my $sum = sum $s =~ m{ \d+ }xmsg;

Re: Remove letters from variables used in math operation?
by shadowfox (Sexton) on Dec 08, 2012 at 21:32 UTC
    Both great and working suggestions, thanks guys! I'll probably go with what AnomalousMonk suggested as it is more of what I wanted to do, but thank you also tobyink, I didn't realize I could turn off specific warnings I don't need like that, it's good to have options :)
Re: Remove letters from variables used in math operation?
by BillKSmith (Chaplain) on Dec 09, 2012 at 03:22 UTC
    The use of several modules can increase the flexability of your code without introducing the potential errors mentioned by other responders.
    use strict; use warnings; use v5.10.1; use Readonly; use List::Util qw(sum); use Regexp::Common; Readonly::Scalar my $NUMBER => qr/$RE{num}{real}/; while (my $line = <DATA>){ chop($line); say sum( $line=~/($NUMBER)/g ); } __DATA__ 86f,934e,92,102i,14,19,222,
    Bill
Re: Remove letters from variables used in math operation?
by graff (Chancellor) on Dec 09, 2012 at 03:31 UTC
    If I were expecting extraneous, insignificant letters at the ends of digit strings, and wanted to treat the digits as integers to be summed, ignoring the letters, I'd do it like this:
    while (my $line = <DATA>) { chomp $line; my @fields = split /,/, $line; my @ints = grep /^\d+$/, map { s/^(\d+)[a-z]?$/$1/; $_ } @fields; my $sum = 0; $sum += $_ for ( @ints ); print $sum, "\n"; warn "found non-integer fields at line $.: $line\n" if ( @fields ! += @ints ); } __DATA__ 86f,934e,92,102i,14,19,222,
    The point is, adapting to variable input, and being "permissive" about what counts as usable input, is all well and good, but any variability - any need of flexibility - implies a risk that there might be more variation than expected. (That's just my view based on experience; if you happen to be fully confident about the nature of your input, you can skip this degree of caution.)

    Still, if the input might contain things that, based on the OP description, really shouldn't happen (e.g. "23e45" or "10/15" or "-0.9%" or ...), it seems worthwhile to get warnings about that. Even if those things don't ever show up, there's no harm done (beyond using some extra cpu cycles).

    And frankly, given the samples shown in the OP, I'd have to ask, just for the sake of being careful: Are you really quite sure that none of those letters were meant to be part of hexadecimal numerics?

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1007926]
Approved by McDarren
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (6)
As of 2014-12-28 22:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (183 votes), past polls