BBQ has asked for the wisdom of the Perl Monks concerning the following question:
⭐ (numbers)
We all know that perl is good for it's so called lack of datatype declarations (and a bunch of other things). But what if you WANT to know if your string is an integer? Furthermore, what if your integer has already been formatted?
This is the code that I came up with, but I feel it could be greatly improoved. Suggestions are > welcome!
Originally posted as a Categorized Question.
Re: How to identify a number datatype in a string?⭐
by chromatic (Archbishop) on Apr 02, 2000 at 06:18 UTC
|
The Perl Cookbook suggests that the following regex will match C floats:
$var =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d)?([Ee]([+-]?\d+))?$/;
That may be overkill for your purposes, though.
Update: (Tue Jan 8 16:03:52 UTC 2002) Removed spurious left paren (thanks, Petruchio). | [reply] [d/l] |
Re: How to identify a number datatype in a string?
by vroom (His Eminence) on Jan 18, 2000 at 22:47 UTC
|
#!/usr/bin/perl
# check for numbers with punctuation
use Strict;
# examples for "common-written" numbers
foreach my $var (
# should be false
'','foo 30','.20','20.',',20','20,',
# should be numbers
0,100,'100.23','1,100.23'
) {
if (IsANumber($var)) {
print "True: $var\n";
} else {
print "False: $var\n";
}
}
sub IsANumber {
my $var = $_[0];
if (
# contains digits,commas and 1 period
($var =~ /(^[0-9]{1,}?$)|(\,*?)|(\.{1})/) &&
# does not contain alpha's, more than 1 period
# commas or periods at the beggining and ends of
# each line
!($var =~ /([a-zA-Z])|(^[\.\,]|[\.\,]$)/) &&
# is not null
($var ne '')
) { return(1) }
else { return(0) }
}
| [reply] [d/l] |
Re: How to identify a number datatype in a string?
by astaines (Curate) on Aug 12, 2001 at 04:31 UTC
|
USe an eval, it's correct (by definition) and avoids possible errors
my @numbers = ( '1', '2', '10',
'1.2', '1e2', '1.02e2',
'1.02e-2', 'e-2', 'er',
'et', '0er' );
foreach my $number (@numbers) {
my $test = $number;
eval { $test +=0; };
if ( $@ ) {
print "$number isn't a number \n";
}
}
{QA Editors note: This solution doesn't work as described. See Re: Answer: How to identify a number datatype in a string? for more explanation.}
Edited by davido: Repaired <code> tags, reformatted code. Added editorial note to clarify why this example is broken.
--
Anthony Staines | [reply] [d/l] [select] |
|
Uh, this doesn't seem to work at all...
laptop:~> perl -T
my @numbers = ('1','2','10','1.2','1e2','1.02e2',
'1.02e-2','e-2','er','et','0er',
'total and complete non number stuff');
foreach my $number (@numbers) {
my $test = $number;
eval { $test +=0; };
if ( $@ ) { print "$number isn't a number \n"; }
}
laptop:~>
Here are my particulars...
| [reply] [d/l] [select] |
|
else { print "number: ", $test , "\n"; }
...Apparently, $test is assigned zero (perl 5.8.0) when $number is not a number. Ergo, no errors in eval, no print.
| [reply] [d/l] [select] |
|
|
Re: How to identify a number datatype in a string?
by rbi (Monk) on Apr 13, 2001 at 18:22 UTC
|
I think that both the Cookbook and vroom miss some valid numbers. Here's my proposed checker. HOpe I don't get wrong ones, instead :)
Roberto
#!/usr/bin/perl
# check for numbers with punctuation
use strict;
# examples for "common-written" numbers
foreach my $var (
'','foo 30','.20','20.',',20','20,','1.3E2', '2..3','++3','2.3.',
,'..3', 0,100,'100.23','1,100.23','-3E-2'
) {
print "String: $var\n";
if (IsANumber($var)) {
print "vroom says True, ";
} else {
print "vroom says False, ";
}
if (IsANumberCookbook($var)) {
print "Cookbook says True, ";
} else {
print "Cookbook says False, ";
}
if (IsANumberMine($var)) {
my $out = $var * $var;
print "I say True and square is $out\n\n";
} else {
print "I say False\n\n";
}
}
sub IsANumber {
# vroom version
my $var = $_[0];
if (
# contains digits,commas and 1 period
($var =~ /(^[0-9]{1,}?$)|(\,*?)|(\.{1})/) &&
# does not contain alpha's, more than 1 period
# commas or periods at the beggining and ends of
# each line
!($var =~ /([a-zA-Z])|(^[\.\,]|[\.\,]$)/) &&
# is not null
($var ne '')
) { return(1) }
else { return(0) }
}
sub IsANumberCookbook {
# Perl Cookbook version
my $var = $_[0];
if (
$var =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d)?([Ee]([+-]?\d+)
+)?$/
) { return(1) }
else { return(0) }
}
sub IsANumberMine {
# my version
my $var = $_[0];
if (
$var =~ /^([+-]?)(\d+\.|\.\d+|\d+)\d*([Ee]([+-]?\d+))
+?$/
) { return(1) }
else { return(0) }
}
| [reply] [d/l] |
Re: How to identify a number datatype in a string?
by jdhedden (Deacon) on Sep 23, 2005 at 17:52 UTC
|
#!/usr/bin/perl
use strict;
use warnings;
use Scalar::Util qw(looks_like_number);
my $x = $ARGV[0];
if (looks_like_number($x)) {
if (int($x) == $x) {
print("$x is an integer\n");
} else {
print("$x is numeric\n");
}
} else {
print("Your input was not numeric\n");
}
| [reply] [d/l] [select] |
Re: How to identify a number datatype in a string?
by Anonymous Monk on May 06, 2002 at 06:12 UTC
|
Identify String or number: Ben Young;
I tried this and it only fails on $x = '0.0', but not $x = 0.0
if (($m == 0) && !($m eq '0')) {print "string\n";} else {print "number
+\n";}
It works since PERL treats strings as 0 in numeric tests. (It also pulls numbers out of strings if the numbers come first)
Edited by davido: Added code tags. Reformatted. | [reply] [d/l] [select] |
Re: How to identify a number datatype in a string?
by Anonymous Monk on Jul 31, 2002 at 15:37 UTC
|
The first regex given on this page to identify a number fails with:
"1.233e+23",
"1.233"
but succeeds with:
"1.2e+233"
Appears to be some sort of problem with multiple digits after a decimal point.
The regex is:
/^([+-]?)(?=\d|\.\d)\d*(\.\d)?([Ee]([+-]?\d+))?$/
A slightly modified version which does work for the given cases:
/^([+-]?)(?=\d|\.\d+)\d*(\.\d+)?([Ee]([+-]?\d+))?$/
The only difference is the extra plus's after each \.
Edited by davido: Added <code> tags. | [reply] [d/l] [select] |
Re: How to identify a number datatype in a string?
by Bilbo (Pilgrim) on May 09, 2003 at 13:08 UTC
|
The mehod suggested by astaines works but the script
he gives does not because perl only warns about adding
to non-numeric variables, so this is not caught by the
eval. It is therefore necessary to make warnings fatal
within the eval block:
sub is_number {
my $test = shift;
eval {
local $SIG{__WARN__} = sub {die $_[0]};
$test += 0;
};
if ($@) {return 0;} else {return 1;}
}
| [reply] [d/l] |
|
|