Re: How to capture the "isn't numeric" warning?
by Cristoforo (Curate) on Jun 15, 2019 at 00:16 UTC
|
| [reply] |
|
You can get the same answer directly from the FAQ.
perldoc -q "How do I determine whether a scalar is a number"
| [reply] [d/l] |
Re: How to capture the "isn't numeric" warning?
by LanX (Saint) on Jun 15, 2019 at 00:32 UTC
|
my $result;
{
my $flag;
local $SIG{__WARN__} = sub {
# catch error in @_, set $flag
};
$result = int($x);
something_different($x,$result) if $flag;
}
See Perl's Warn and Die Signals for a general discussion.
HTH! :)
| [reply] [d/l] |
|
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;
}
| [reply] [d/l] |
|
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] |
|
|
|
|
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] |
|
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] |
|
|
|
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] |
|
|
|
|
Re: How to capture the "isn't numeric" warning?
by hippo (Bishop) on Jun 15, 2019 at 09:32 UTC
|
#!/usr/bin/env perl
use strict;
use warnings;
use Try::Tiny;
my $X = "abc";
try {
use warnings FATAL => 'numeric';
$X = int($X);
} catch {
$X = "This should have been a number";
};
print $X;
| [reply] [d/l] |