Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations dencom on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

String or number 1

Status
Not open for further replies.

prex1

Programmer
May 10, 2007
482
IT
I need a routine that distinguishes between a number (in decimal representation) and a string that's not a legal number (let's say it returns 1 for a number, 0 otherwise).
As perl treats any string, that starts with a legal number, as a number, the simple solution
$numorstr*1?1:0
doesn't work (and of course doesn't give the correct answer for the number 0).
Assuming the checked value is not a reference, below is what I've come up with this problem: can anyone see a simpler (or more robust) solution?
Code:
sub isnumber{
    #returns 1 if passed value is a valid number in decimal representation
    #0 otherwise
  local($_);
  for($_[0]){
    s/^\s+//;
      #leading spaces considered as non influent
    return 0 unless length;
      #a white or null string or an undef is considered a string
    s/0+/0/g;
      #multiple 0's treated as one (a string of many 0's is a 0)
    return 1 if$_ eq'0';
      #a single 0 is a number
    s/^[\+\-]{1}//;
      #only single leading +/- allowed
    s/\.{1}//;
      #only a single occurrence of decimal point allowed
    s/^[0-9]+//g;
      #strip away leading figures
    if(s/^e//i){
        #strip exponential symbol (now leading, if any)
      return 0 unless length;
        #no exponent:illegal for a number
      s/^[\+\-]{1}//;
        #only single leading +/- allowed in the exponent
      s/^[0-9]+//g;
        #strip away figures of the exponent
    }
    return length()?0:1;
      #if length==0 was a number
  }
}
NOTE: perl allows underscores in number representation as thousands separators, but from some tests I assumed that this is only allowed when the number is input as such (e.g. $a=1_000 without string delimiters) and that perl strips away those underscores in compiling that type of representation. Hence underscores are not specially treated in the routine.

prex1
: Online tools for structural design
: Magnetic brakes for fun rides
: Air bearing pads
 
Hi

While you wrote "in decimal representation", I would go with this :
Code:
sub isnumber
{
  $_[0] eq $_[0]+0
}
Note that I do not use strict and/or other similar.

Feherke.
 
feherke,
to perl the string '1abc' is treated as the number 1 when used as a number (e.g. in a numerical addition or multiplication).
Hence '1abc'+0 returns 1.
To me '1abc' is a string, and I need to recognize it as such.

prex1
: Online tools for structural design
: Magnetic brakes for fun rides
: Air bearing pads
 
Hi

prex1 said:
Hence '1abc'+0 returns 1.
Correct, but my function uses [tt]'1abc' eq '1abc'+0[/tt] , which returns false.
Code:
[blue]master #[/blue] cat | perl -ne 'sub isnumber{$_[0]eq$_[0]+0};chomp;print "$_ : ".&i
snumber($_)."\n"' <<EOF
> lol
> [red]1[/red]ol
> [red]10[/red]l
> l[red]0[/red]l
> l[red]01[/red]
> lo[red]1[/red]
> [red]101[/red]
> EOF
lol :
[red]1[/red]ol :
[red]10[/red]l :
l[red]0[/red]l :
l[red]01[/red] :
lo[red]1[/red] :
[red]101[/red] : 1
Note that I colored the digits with red. ( Yep, my example was not the best, but I am lazy to rewrite it now... )

Feherke.
 
Thanks, feherke, I got it.
However your method doesn't work in quite common cases, like:
00
03
+1
1.0
and almost all exponential notations, if the exponent is not written in perl canonical form (3 digits,sign always present).

prex1
: Online tools for structural design
: Magnetic brakes for fun rides
: Air bearing pads
 
Hi

Yes, as I mentioned it is based on the words "in decimal representation", so I just ignored the octals. But you are right, for example that unary plus should be accepted.

Feherke.
 
Yes, I had the same problem.
I wrote this little routine that seems to work fine, but it might well be that I overlooked some things...

On it says:

$n = 1234; # decimal integer
$n = 0b1110011; # binary integer
$n = 01234; # octal integer
$n = 0x1234; # hexadecimal integer
$n = 12.34e-56; # exponential notation
$n = "-12.34e56"; # number specified as a string
$n = "1234"; # number specified as a string

So my routine is this:

sub isNumber {
my ($sNumber) = @_;

return($sNumber =~ /^\d+(\.\d*)?(e\d+)?$/ || # 1.23e34
$sNumber =~ /^0b[01]+$/ || # 0b101
$sNumber =~ /^0x[12345678abcdefgh]+$/i # 0x2134 )
}

Does that make sense..?!?
 
It makes sense MacTommy, but see the link I posted above for other solutions if interested.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
MacTommy: your regexp for catching hexadecimal numbers is missing 0 and 9, which are valid characters and includes g and h, which aren't.
 
Yes, right you are.

I see now that I skipped some +/- signs anyway...
 
[blush]
No, you are also right.
Pretty sloppy coding, I realise now...
[/blush]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top