When you use a Perl string in a numeric context, such as a numeric comparison, it recognizes the starting part that looks like a decimal number and ignores the stuff after that. Whatever it recognizes becomes the number.
It follows these basic rules:
- Ignore leading whitespace. This is handy when you extract a field out of columnar data and the number doesn't take up the entire column.
- Allow for a single leading sign (
+ or -)
- Skip leading zeros (so, no octal)
- Capture decimal ASCII digits (0,1,2,3,4,5,6,7,8,9), allowing for a single decimal point (so, no semantic versioning numbers)
- Stop at the first non-decimal-digit character
- Whatever you have so far is the number. If you have nothing, the number is 0.
There are some things to note, though:
- Adding 0 to a string is a common way to force numeric mode.
- Underscores in strings are just underscores. You can use underscores to separate digits in number literals but not in strings. So,
123_456 is 123456 because the perl parser handles the _, but '123_456' is just 123.
- However, if the first characters (excluding the sign) are "Inf", in any case, the string converts to "Inf" and includes the
- sign but not the + sign. This is the special IEEE value of Infinity.
- However, if the first characters (excluding the sign) are "NaN", in any case, the string converts to "Nan" and excludes either sign. This is the special "Not a number" value.
Here are some examples:
#!perl
use v5.10;
use utf8;
use open qw(:std :utf8);
my @strings = qw(
-5 +7 +006 -01 00
+.1234 -.9876 .657 ..890 1.2.3
١٢٣
- + +-657
12a34 a987 123fred 0456barney
0x12 12_34 0177
NaN -NaN NAN
Inf +Inf -Inf INF Infamy Infinity
);
push @strings, " 432", "+ 123", " -987", " +063"," NaN", " Inf", '';
foreach my $string ( @strings ) {
printf "%-12s => %s\n", qq('$string'), 0 + $string;
}
And the output:
'-5' => -5
'+7' => 7
'+006' => 6
'-01' => -1
'00' => 0
'+.1234' => 0.1234
'-.9876' => -0.9876
'.657' => 0.657
'..890' => 0
'1.2.3' => 1.2
'١٢٣' => 0
'-' => 0
'+' => 0
'+-657' => 0
'12a34' => 12
'a987' => 0
'123fred' => 123
'0456barney' => 456
'0x12' => 0
'12_34' => 12
'0177' => 177
'NaN' => NaN
'-NaN' => NaN
'NAN' => NaN
'Inf' => Inf
'+Inf' => Inf
'-Inf' => -Inf
'INF' => Inf
'Infamy' => Inf
'Infinity' => Inf
' 432' => 432
'+ 123' => 0
' -987' => -987
' +063' => 63
' NaN' => NaN
' Inf' => Inf
'' => 0
Finally, there's another interesting thing about Perl scalars. When you use a string as a number, Perl converts the string to a number and remembers the conversion. It does not, however, change the string. Devel::Peek shows you the innards of Perl data structures.
#!perl
use v5.10;
use Devel::Peek;
select(STDERR); $|++; # just to order the output from Dump
my $string = '123fred';
say "string is <$string>";
Dump( $string );
say '-' x 40;
my $n = $string + 0;
say "string is <$string>";
Dump( $string );
Here's the output. At first, $string has a PV (pointer value) for a string. After the numeric operation, it also has IV and NV values for numbers.
string is <123fred>
SV = PV(0x7f8be980cab0) at 0x7f8bea0160f8
REFCNT = 1
FLAGS = (POK,IsCOW,pPOK)
PV = 0x7f8be9610ca0 "123fred"\0
CUR = 7
LEN = 10
COW_REFCNT = 1
----------------------------------------
string is <123fred>
SV = PVNV(0x7f8be980ac50) at 0x7f8bea0160f8
REFCNT = 1
FLAGS = (POK,IsCOW,pIOK,pNOK,pPOK)
IV = 123
NV = 123
PV = 0x7f8be9610ca0 "123fred"\0
CUR = 7
LEN = 10
COW_REFCNT = 1