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% --
| [reply] [d/l] [select] |
|
|
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
| [reply] |
|
|
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.
| [reply] [d/l] [select] |
|
|
Re^3: How to capture the "isn't numeric" warning?
by AnomalousMonk (Archbishop) on Jun 15, 2019 at 08:10 UTC
|
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: <%-{-{-{-<
| [reply] [d/l] [select] |
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 | [reply] [d/l] |
|
|
$ 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). | [reply] [d/l] [select] |
|
|
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 | [reply] [d/l] [select] |
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.
| [reply] |
|
|
| [reply] |
|
|
| [reply] [d/l] [select] |
|
|
|
|
|
|
|
| [reply] |