thanos1983 has asked for the wisdom of the Perl Monks concerning the following question:
Dear Monks,
I found on the perlfaq4 the following code:
use 5.010; given( $number ) { when( /\D/ ) { say "\thas nondigits"; continue } when( /^\d+\z/ ) { say "\tis a whole number"; continue } when( /^-?\d+\z/ ) { say "\tis an integer"; continue } when( /^[+-]?\d+\z/ ) { say "\tis a +/- integer"; continue } when( /^-?(?:\d+\.?|\.\d)\d*\z/ ) { say "\tis a real number"; continue } when( /^[+-]?(?=\.?\d)\d*\.?\d*(?:e[+-]?\d+)?\z/i) { say "\tis a C float" } }
I am trying to find a way to determine the element from the array if it is an integer, decimal or float. But I am guessing that I am missing something.
I have modified the code for testing purposes:
#!/usr/bin/perl use strict; use warnings; my @numbers = (1, -1, 123.1, 0.1); foreach my $number (@numbers) { if ($number =~ /\D/ ) { print "The $number has nondigits\n"; } elsif ($number =~ /^\d+\z/ ) { print "The $number is a whole number\n"; } elsif ($number =~ /^-?\d+\z/ ) { print "The $number is an integer\n"; } elsif ($number =~ /^[+-]?\d+\z/ ) { print "The $number is a +/- integer\n"; } elsif ($number =~ /^-?(?:\d+\.?|\.\d)\d*\z/ ) { print "The $number is a real number\n"; } elsif ($number =~ /^[+-]?(?=\.?\d)\d*\.?\d*(?:e[+-]?\d+)?\z/i ) { print "The $number is a C float\n"; } }
But I am getting, not the expected output:
The 1 is a whole number The -1 has nondigits The 123.1 has nondigits The 0.1 has nondigits
I would expect something like:
The 1 is a +/- integer The -1 is a +/- integer The 123.1 is a C float The 0.1 is a C float
Update: I was playing around to see if by modifying the numbers to string in the array will affect the output. I modified the my @numbers = (1, 1.0, 123.1, 0.1); to my @numbers = qw(1, 1.0, 123.1, 0.1);. That was the only modification that I applied and the output of the script changes only the first line The 1 is a whole number to The 1, has nondigits.
At this point I am sure that I am doing something completely wrong but I can not figure out what is it. Can someone help understand why I can not get the expected output?
Update 2: I also found from Is it a Number?.
my @numbers = ("1", "-1", "123.1", "0.1"); foreach my $number (@numbers) { my $integer = is_integer($number); print "$number is Integer\n" if ($integer); my $float = is_float($number); print "$number is Float\n" if ($float); } sub is_integer { $_[0] =~ /^[+-]?\d+$/ } sub is_float { $_[0] =~ /^[+-]?\d+\.?\d*$/ } __END__ Output: 1 is Integer 1 is Float -1 is Integer -1 is Float 123.1 is Float 0.1 is Float
Update 3: As shmem pointed out, what I was afraid of, that regex compare against strings. So I guess the array to compare against should be modified to my @numbers = qw(1 1.0 123.1 0.1); as Laurent_R has pointed out. So the code should be like this:
#!/usr/bin/perl use strict; use warnings; my @numbers = qw(1 -1 123.1 0.1 Characters); foreach my $number (@numbers) { if ($number =~ /^[+-]?\d+\z/ ) { print "The $number is a +/- integer\n"; } elsif ($number =~ /^[+-]?(?=\.?\d)\d*\.?\d*(?:e[+-]?\d+)?\z/i ) { print "The $number is a C float\n"; } elsif ($number =~ /\D/ ) { print "The $number has nondigits\n"; } } __END__ The 1 is a +/- integer The -1 is a +/- integer The 123.1 is a C float The 0.1 is a C float The Characters has nondigits
Which starts to make more sense.
Update 4: An alternative and possibly better solution would be to use Switch. It will give us the same output.
#!/usr/bin/perl use strict; use warnings; my @numbers = qw(1 -1 123.1 0.1 Characters); foreach my $number (@numbers) { checkInputStringWithSwitchConditions($number); } sub checkInputStringWithSwitchConditions { use Switch; switch ($_[0]) { case /^[+-]?\d+\z/ { print "The $_[0] is a + +/- integer\n" } case /^[+-]?(?=\.?\d)\d*\.?\d*(?:e[+-]?\d+)?\z/i { print "The $_[0 +] is a C float\n" } case /\D/ { print "The $_[0 +] has nondigits\n" } else { print "Non of the c +ases where True\n" } } } __END__ The 1 is a +/- integer The -1 is a +/- integer The 123.1 is a C float The 0.1 is a C float The Characters has nondigits
Update 5: By comparing the two methods together by using Benchmark, we can see that the Switch method is a better and faster method to use.
#!/usr/bin/perl use strict; use warnings; use Benchmark qw( timethese cmpthese ) ; my @numbers = qw(1 -1 123.1 0.1 Characters); my $swithRefLoop = 'foreach my $number (@numbers) { checkInputStringWithSwitchConditions($number); }'; my $ifAndElsIfRefLoop = 'foreach my $number (@numbers) { checkInputStringWithIfAndElseConditions($number); }'; my $Benchmark = timethese( -10, { IfAndElsIfLoop => $ifAndElsIfRefLoop, SwitchLoop => $swithRefLoop, } ); cmpthese $Benchmark; sub checkInputStringWithSwitchConditions { use Switch; switch ($_[0]) { case /^[+-]?\d+\z/ { print "The $_[0] is a + +/- integer\n" } case /^[+-]?(?=\.?\d)\d*\.?\d*(?:e[+-]?\d+)?\z/i { print "The $_[0 +] is a C float\n" } case /\D/ { print "The $_[0 +] has nondigits\n" } else { print "Non of the c +ases where True\n" } } } sub checkInputStringWithIfAndElseConditions { if ( $_[0] =~ /^[+-]?\d+\z/ ) { print "The $_[0] is a +/- integer\n"; } elsif ( $_[0] =~ /^[+-]?(?=\.?\d)\d*\.?\d*(?:e[+-]?\d+)?\z/i ) { print "The $_[0] is a C float\n"; } elsif ( $_[0] =~ /\D/ ) { print "The $_[0] has nondigits\n"; } } __END__ Benchmark: running IfAndElsIfLoop, SwitchLoop for at least 10 CPU seco +nds... IfAndElsIfLoop: 11 wallclock secs (10.04 usr + -0.00 sys = 10.04 CPU) +@ 4954765.54/s (n=49745846) SwitchLoop: 9 wallclock secs (10.04 usr + 0.00 sys = 10.04 CPU) @ 56 +91789.84/s (n=57145570) Rate IfAndElsIfLoop SwitchLoop IfAndElsIfLoop 4954766/s -- -13% SwitchLoop 5691790/s 15% --
Thank you all for your time and effort reading and replying to my question.
|
|---|