in reply to Re: How to capture the "isn't numeric" warning?
in thread How to capture the "isn't numeric" warning?

Oh, wow, THANK YOU! That's exactly what I wanted to know. So, what do you think of my sub? Lol It seems to work...

#!/usr/bin/perl -w use strict; use warnings; print isNumber("abc"); # returns 0 print "\n"; print isNumber("123"); # returns 1 print "\n"; sub isNumber { @_ or return 0; my $N = shift; defined $N or return 0; my $R = 1; { local $SIG{__WARN__} = sub { $R = 0; }; $N = int($N); } return $R; }

Replies are listed 'Best First'.
Re^3: How to capture the "isn't numeric" warning?
by haukex (Archbishop) on Jun 15, 2019 at 10:01 UTC
    That's exactly what I wanted to know. So, what do you think of my sub?

    Sorry, but I don't think it's a good idea. For one, the signal handler will fire on any warning. Scalar::Util's looks_like_number (a core module) calls the internal Perl function that checks if a string looks like a number, so this is just a really convoluted way of calling that function. In your OP, you said "Is there a faster way to test if a variable is a number?", and this is definitely a much slower way to do so - in fact, roughly 38 times slower! As numerous people have said, just use looks_like_number.

    use warnings; use strict; use Benchmark qw/cmpthese/; use Scalar::Util qw/looks_like_number/; sub isNumber { @_ or return 0; my $N = shift; defined $N or return 0; my $R = 1; { local $SIG{__WARN__} = sub { $R = 0; }; $N = int($N); } return $R; } cmpthese(-2, { isNumber => sub { isNumber("123") or die; isNumber("-5e7") or die; isNumber("abc") and die; isNumber("") and die; }, looks_like_number => sub { looks_like_number("123") or die; looks_like_number("-5e7") or die; looks_like_number("abc") and die; looks_like_number("") and die; } }); __END__ Rate isNumber looks_like_number isNumber 153840/s -- -97% looks_like_number 5991731/s 3795% --
      For one, the signal handler will fire on any warning.

      Yes, the same thought occurred to me ... but then I couldn't come up with an argument that could be passed to isNumeric() && elicit a warning other than the "isn't numeric" one.
      Is there such an argument ?

      Cheers,
      Rob

        You could get it from an object that overloads numification (0+) or int, and the sub handling the overload warns.

        One could argue that isNumber gives the better result in that situation.

Re^3: How to capture the "isn't numeric" warning?
by AnomalousMonk (Archbishop) on Jun 15, 2019 at 08:10 UTC

    I agree with syphilis here (update: and haukex here) that Scalar::Util::looks_like_number() looks like a better solution. One problem with this is that it's dependent upon the state of warnings in the enclosing scope:

    c:\@Work\Perl\monks>perl -le "use strict; use warnings; ;; no warnings 'numeric'; print 'numeric warning DISabled'; ;; print q{'abc' }, isNumber('abc'); print q{'123' }, isNumber('123'); print q{123 }, isNumber(123); ;; sub isNumber { @_ or return 0; my $N = shift; defined $N or return 0; my $R = 1; { local $SIG{__WARN__} = sub { $R = 0; }; $N = int($N); } return $R; } " numeric warning DISabled 'abc' 1 '123' 1 123 1
    A fix (if you're wedded to isNumber()) might be something like:
    c:\@Work\Perl\monks>perl -le "use strict; use warnings; ;; no warnings 'numeric'; print 'numeric warning DISabled'; ;; print q{'abc' }, isNumber('abc'); print q{'123' }, isNumber('123'); print q{123 }, isNumber(123); print q{undef }, isNumber(undef); print q{() }, isNumber(); ;; sub isNumber { my $numeric = 1; use warnings 'numeric'; local $SIG{__WARN__} = sub { $numeric = 0; }; my $x = int $_[0]; return $numeric; } " numeric warning DISabled 'abc' 0 '123' 1 123 1 undef 0 () 0
    A test plan: More test cases would be wise: there are no negatives, +0, +1, '+0', '+1', +123e+45, etc.


    Give a man a fish:  <%-{-{-{-<

Re^3: How to capture the "isn't numeric" warning?
by syphilis (Archbishop) on Jun 15, 2019 at 06:18 UTC
    Hi,

    I think isNumber() is doing the same as Scalar::Util::looks_like_number(), except that the former is returning '0' for FALSE, whereas the latter returns '' (the empty string) for FALSE.
    One slight advantage I can see in using looks_like_number() is that it doesn't require the warnings pragma.
    And, I think, isNumber() is rather convoluted in that int($N) is going to perform essentially the same check as looks_like_number() and then catch the warning if that check fails, before assigning 0 to $R and returning. So it's also a little less efficient.

    But that just makes isNumber() the more interesting solution !

    Cheers,
    Rob

      whereas the latter returns '' (the empty string) for FALSE.

      It does not.

      $ perl -MScalar::Util=looks_like_number -we' CORE::say 0+""; ' Argument "" isn't numeric in addition (+) at -e line 2. 0 $ perl -MScalar::Util=looks_like_number -we' CORE::say 0+looks_like_number("abc"); ' 0

      It returns the usual empty string, 0, 0.0 triple-var Perl uses for false (sv_no).

        It does not.

        Really ??
        Could you show me a Devel::Peek::Dump output for the scalar returned by S::U::looks_like_number('abc') - one that shows that the empty string is not returned ?
        (Also, the version number of Scalar::Util on which this happens, and the 'perl -V' output.)

        Scalar-Util-1.45 (perl-5.16.0):
        C:\>perl -MScalar::Util -MDevel::Peek -le "Dump(Scalar::Util::looks_li +ke_number('abc'));" SV = PVNV(0x726f74) at 0x723250 REFCNT = 2147483647 FLAGS = (IOK,NOK,POK,READONLY,pIOK,pNOK,pPOK) IV = 0 NV = 0 PV = 0x7229b4 ""\0 CUR = 0 LEN = 12
        Scalar-Util-1.5 (perl5.30.0):
        C:\>perl -MScalar::Util -MDevel::Peek -le "Dump(Scalar::Util::looks_li +ke_number('abc')); SV = PVNV(0x2ea0a8) at 0x2e8150 REFCNT = 2147483647 FLAGS = (IOK,NOK,POK,READONLY,PROTECT,pIOK,pNOK,pPOK) IV = 0 NV = 0 PV = 0x6ff24e83 "" CUR = 0 LEN = 0
        My assertion the "the empty string is returned" could well be deemed incomplete because the IV and NV slots are also filled.
        But the PV slot definitely contains the empty string, and it's the contents of the PV slot that are displayed by print().

        AFAICS, any assertion that looks_like_number does not return the empty string for FALSE is complete bullshit.
        (But I upvoted your post anyway - on the strength of the boldness and abrasiveness of its opening assertion.)

        Cheere,
        Rob
Re^3: How to capture the "isn't numeric" warning?
by LanX (Saint) on Jun 15, 2019 at 13:16 UTC
    Hi harangzsolt33,

    It really depends on the use case, you haven't been too clear about this.

    What I've shown is a kind of exception handling, (the difference to hippo's solution being that it is only catching warnings and not fatals)

    That's ok if you want to monitor complicated code or volatile input.

    Or if you have to deal with different unpredictable warnings.

    > So, what do you think of my sub?

    In this particular case I (like the others replying) have problems to see the advantage over Scalar::Util 's looks_like_number().

    Unless you can show a case where the latter fails to avoid the warning.

    And you should at least check which warnings were triggered.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

      Hmm... All right, so it looks like looks_like_number() is better. Usually when I read this forum or ask something, I always learn something and then something extra on top of that. In this case, I learned how to capture warnings, how to turn off warnings. (And don't laugh, my assumption was that you can't just create a block { ... } without having a "for" or "sub" or an "if" keyword in front of it. In other programming languages, you get an error if you just create a block with no keyword in front of it. In perl, this is allowed, and it is something that I just discovered. Lol)

      Thank you for your informative answers!!!

        Even if bare blocks weren't allowed in Perl, you could just use a do { ... } block, or a for loop that only has one iteration.

        your welcome! :)

        > I always learn something and then something extra on top of that

        That's why the monastery is so great!

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery FootballPerl is like chess, only without the dice