gghelpneeded has asked for the wisdom of the Perl Monks concerning the following question:

Fellow Monks

I was working on an arithmetic script when I received an interesting error

Argument "(49)" isn't numeric in subtraction (-) and so on

What constitutes a number in parentheses as nonnumeric? What should I do, granted I am working from a data set that is very large and more than one numeric value is in parentheses?

Sample Data

(15) 20 (3) 50

Sample code that is being used to determine these values

$amount{$stock}+=($value[1] - $value[0])

Cheers.

Replies are listed 'Best First'.
Re: numbers in parentheses not considered numeric values??
by roboticus (Chancellor) on Aug 07, 2015 at 22:32 UTC

    gghelpneeded:

    It's telling you that the string value "(49)" isn't numeric. Whenever you use a string as a number, perl tries to convert the string to a number using some simple rules. Usually it works just the way you want, but it can't possibly always do what you want.

    Consider these examples:

    $ cat x.pl #!/usr/bin/env perl use strict; use warnings; my @stuff = (49, (49), "49", "(49)", "123", "76 trombones", "123 E 31st", "123E31st street"); for my $t (@stuff) { print "t=<$t>, t+0=", $t+0, "\n\n"; } Roboticus@Waubli ~ $ perl x.pl t=<49>, t+0=49 t=<49>, t+0=49 t=<49>, t+0=49 Argument "(49)" isn't numeric in addition (+) at x.pl line 8. t=<(49)>, t+0=0 t=<123>, t+0=123 Argument "76 trombones" isn't numeric in addition (+) at x.pl line 8. t=<76 trombones>, t+0=76 Argument "123 E 31st" isn't numeric in addition (+) at x.pl line 8. t=<123 E 31st>, t+0=123 Argument "123E31st street" isn't numeric in addition (+) at x.pl line +8. t=<123E31st street>, t+0=1.23e+33

    So if you really want to treat them as numbers, you'll need to come up with the appropriate rules (and code) to determine what number to convert them into. If it's as simple as stripping off parenthesis, you could do it with s/[()]//g, but be sure to think about all the special cases you may run into...

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      thanks for that example, further solidifying the explanation above. Both examples get the point across greatly!

      when you speak of stripping off parenthesis do you mean through the code itself or the find and replace feature on gedit?

        gghelpneeded:

        As the Anonymous Monk mentioned, in your code. Different sources of data may have different quirks, so you need to know about your data source to figure out the best way to clean up the data. You want to be careful with your fixes, though, to make sure you make the appropriate conversions.

        For example, in some accounting reports, parenthesis around a number may indicate that it's negative value rather than positive. Other systems may include commas, currency symbols or other formatting information. Yet other systems use a trailing sign on the data. Once you find out all the quirks, you shouldn't have too much trouble writing an appropriate subroutine to clean up and convert the data to the form you need.

        ...roboticus

        When your only tool is a hammer, all problems look like your thumb.

        In the code itself, see example below:

        #!/usr/bin/perl -l # http://perlmonks.org/?node_id=1137878 use strict; use warnings; $| = 1; while(<DATA>) { my @value = split; tr/()//d for @value; # THE FIX print $value[1] - $value[0]; } __DATA__ (15) 20 (3) 50
Re: numbers in parentheses not considered numeric values??
by ikegami (Patriarch) on Aug 07, 2015 at 22:17 UTC
    What constitutes a number in parentheses as nonnumeric?

    I'm not sure why you ask since even you don't think it's a number. If you did, you wouldn't have said "a number in parentheses"; you would simply have said "a number".

    The result of the string evaluated as Perl code would be a number, but the addition operator isn't about to start evaluating data as code.

      I can't parentheses then? Bummer. I thought perl would allow it since parentheses are common in arithmetic problems.
        The addition operator adds numbers, not arithmetic expressions. You can use all the parentheses you want in your arithmetic expressions, but not in your numbers.
Re: numbers in parentheses not considered numeric values??
by davido (Cardinal) on Aug 08, 2015 at 14:44 UTC

    The question should really be titled, "What strings can Perl treat as numbers?", but even that has a nuance.

    Perl's data types are polymorphic, and its operators are mostly monomorphic. This means that you can do this:

    my $value = "abc" + "def"; print "$value\n";

    And quietly, behind the scenes, the string "abc" and the string "def" will be upgraded to numbers. And $value will contain 0.

    It is how Perl performs these polymorphic mutations that is tripping you up. The rules are a little hard to remember. But one easy way to remember most of the cases (while missing a few special cases) is that if the string starts with numeric digits, or with a decimal followed by numeric digits, and possibly preceded by a sign, Perl will be able to use the sign and digits in its transmutation. Therefore, a string that looks like "123abc" will be seen in numeric context as the number 123. But a string that looks like "abc123" will be seen as 0 in numeric context.

    You are asking about the string "(123)". That string starts with a paren, which is not a digit or a sign. Perl will see it as a non-numeric string, and will treat it as numeric zero in numeric context.

    Earlier I said "quietly, behind the scenes", and that's mostly true, unless you enable warnings, in which case string upgrades to their numeric value will trigger a warning if that value is zero and is not based on finding a number at the start of the string.

    Update: I realized this doesn't really answer how to make a string be treated as an expression (which is what you are requesting), rather than as a number. There is no simple answer, because strings are just a bunch of characters with very simple semantic meaning. If you want to treat the string with more elaborate semantics, you need a way to accomplish that. The best way is to lex and parse the string. If you don't want to write a lexer and parser yourself, you have options. The simplest option is to eval the string. But that carries risks because Perl's eval will treat the string as Perl code, which means it gives the string more elaborate semantics than you probably intend. But if you are certain that the string cannot be meddled with, and certain that it will look as you expect, string eval can be a reasonable solution.

    Another solution is to use a CPAN module that handles mathematical lexing, parsing, and evaluating. Math::Expression is a good starting point.

    A naive approach would be to take "(42)" and use tr/// or s/// to strip away the parts you don't want. That may be just fine if you have only simple cases to deal with. But if the input potentially gets more complex than just stripping parens, you could end up bolting on more and more one-off substitutions, and the result could become difficult to maintain and debug.


    Dave

Re: numbers in parentheses not considered numeric values??
by anonymized user 468275 (Curate) on Aug 08, 2015 at 12:08 UTC
    The code works when I test it, so your example is probably not representative of the problem. You could put eval() around each variable that may contain an expression to widen the cases that will be evaluated properly.

    One world, one people