Re: Illegal octal digit error
by GrandFather (Saint) on Jun 06, 2009 at 07:53 UTC
|
Do you want to preserve the leading 0 in the key? If so then you must quote the string because otherwise Perl will treat the digits as an octal number (as you have already found) and the key will end up as the stringised version of the number. Consider:
use strict;
use warnings;
my %hash;
$hash{01} = 'one';
$hash{07} = 'seven';
$hash{010} = 'eight';
$hash{10} = 'ten';
$hash{'01'} = "'one'";
$hash{'07'} = "'seven'";
$hash{'010'} = "'eight'";
$hash{'10'} = "'ten'";
print "$_ => $hash{$_}\n" for sort keys %hash;
Prints:
01 => 'one'
010 => 'eight'
07 => 'seven'
1 => one
10 => 'ten'
7 => seven
8 => eight
True laziness is hard work
| [reply] [d/l] [select] |
|
This is surprising given the description of '=>' in perlop:
The "=>" operator is a synonym for the comma, but forces any word (consisting entirely of word characters) to its left to be interpreted as a string (as of 5.001). This includes words that might otherwise be considered a constant or function call.
And perlre defines a word character (\w) as:
A "\w" matches a single alphanumeric character (an alphabetic character, or a decimal digit) or "_"
Yet any collection of word characters that can be interpreted as a numeric constant is, and the result stringified. This includes octal, hex and some scientific notation (without period: e.g. 12e3).
Am I misreading perlsyn or does it say that 07, 0666, 0x123 and 12e3 or even 08, 0abc or even 0xyz should all be forced to be interpreted as strings rather than being interpreted as numbers or compile time errors?
| [reply] |
|
| [reply] |
|
|
The LHS of => must be a bareword for the quoting to occur. perldata defines a bareword as "a word that has no other interpretation in the grammar".
The thing is, a bareword "will be treated as if it were a quoted string." That means => does nothing except prevent the default behaviour from being "outlawed" using use strict 'subs';.
I don't know what the wording should be, but the docs for => need fixing. Submit a patch!
| [reply] [d/l] [select] |
|
|
|
|
That wording is incorrect. "=>" quotes anything on the left that looks like a valid (non-punctuation, user-definable) identifier name. And identifiers cannot start with a digit.
$ perl -Mstrict -e 'print foo => "\n"'
foo
$ perl -Mstrict -e 'print foo::bar => "\n"'
foo::bar
$ perl -Mstrict -e 'print foo:bar => "\n"'
syntax error at -e line 1, near "foo:"
Execution of -e aborted due to compilation errors.
$ perl -Mstrict -e 'print 0foo => "\n"'
syntax error at -e line 1, near "0foo"
Execution of -e aborted due to compilation errors.
$ perl -Mstrict -e "print foo'bar => qq'\n'"
foo::bar
$ perl -Mstrict -e "print foo''bar => qq'\n'"
Bad name after foo' at -e line 1.
$ perl -Mstrict -e "print foo'baz'bar => qq'\n'"
foo::baz::bar
$
| [reply] [d/l] |
|
This is a great post by Grandfather! There is an important part he illustrated that might get missed...notice that there are 8 hash assignment statements, but only 7 lines in printout. What happened? The $hash{10} = 'ten'; statement caused the numeric ten to be converted to string for use as a hash key. The $hash{'10'} = "'ten'"; statement generated the same key and caused 10's value to be overwritten.So what that means is that if you use a numeric value as a hash key, Perl will convert it to a string. There will not be any leading zeroes in that string! The poster looks like he wants a table to translate a number into text months. I suspect that putting '08' in quotes is unlikely to be the best thing here and that the first reply "get rid of the leading zero" is probably better because I suspect this "8" will come from a numeric routine (like a time function) and if it doesn't (like from a webpage, etc) there is any easy way to "get rid of leading zeroes". In Perl everything is a string until used in a numeric context. The below shows one trick that I sometimes use to "delete leading zeroes" without regex...See example 1, this just adds "0" to the string! Example 2 shows some pitfalls of comparing numeric values as strings! Example 3 show's Grandfather's 8 vs 7 keys with another example. The hash lookup needs a string and makes a string if it needs to for use in calculating the actual binary hash key.
#EXAMPLE 1
my $a = "0001";
print "a 1 as string is:$a\n";
$a+=0; # A trick! forces numeric context!!!
print "a 1 as number is:$a\n";
#EXAMPLE 2
my $b="01";
if ($a eq $b)
{
print "$a is eq $b\n";
}
else
{
print "$a is NOT eq $b\n";
}
if ($a == $b)
{
print "$a is == $b\n";
}
else
{
print "$a is NOT == $b\n";
}
#EAMPLE 3
my $string_eight="8";
my $numeric_eight = 8;
if ($string_eight eq $b)
{
print "string $string_eight is eq number $numeric_eight\n";
}
else
{
print "string $string_eight is NOT eq number $numeric_eight\n";
}
my %hash = ('8'=>"string eight", 8 =>'number 8');
print "hash key uses the stringified version of 8: $hash{'8'} or $hash
+{$numeric_eight}\n";
__END__
a 1 as string is:0001
a 1 as number is:1
1 is NOT eq 01
1 is == 01
#string 8 is NOT eq number 8</strike>
hash key uses the stringified version of 8: number 8 or number 8
| [reply] [d/l] [select] |
|
I had some fun with numeric keys, then explored the surprising string 8 is NOT eq number 8, not realizing until much later the cause of this result: if ($string_eight eq $b).
After all, $string_eight and $numeric_eight are 'eq'. And, as I expected, the 'eq' operator causes stringification of the numeric value.
use strict;
use warnings;
use Data::Dumper;
use Devel::Peek;
my %hash = (
1e2 => '100',
100 => '100',
0x64 => '100',
0144 => '100',
);
print Dumper(\%hash);
my $string_eight = '8';
my $numeric_eight = 8;
print "\n\$numeric_eight before use with 'eq'\n";
Dump($numeric_eight);
if ($string_eight eq $numeric_eight) {
print "'eq'\n";
} else {
print "not 'eq'\n";
}
print "\n\$numeric_eight after use with 'eq'\n";
Dump($numeric_eight);
print "\n\$numeric_eight = $numeric_eight\n";
print "\n\$numeric_eight after use in a string (i.e. stringification)\
+n";
Dump($numeric_eight);
if ($string_eight eq $numeric_eight) {
print "not 'eq'\n";
} else {
print "'eq'\n";
}
print "\n\$string_eight then \$numeric_eight after all\n";
Dump($string_eight);
Dump($numeric_eight);
__END__
$VAR1 = {
'100' => '100'
};
$numeric_eight before use with 'eq'
SV = IV(0x97df82c) at 0x97df830
REFCNT = 1
FLAGS = (PADMY,IOK,pIOK)
IV = 8
'eq'
$numeric_eight after use with 'eq'
SV = PVIV(0x97e01b8) at 0x97df830
REFCNT = 1
FLAGS = (PADMY,IOK,POK,pIOK,pPOK) <-- note POK is now set
IV = 8
PV = 0x97ee168 "8"\0 <-- and there is now a PV, CUR
+ and LEN as well as IV
CUR = 1
LEN = 4
$numeric_eight = 8
$numeric_eight after use in a string (i.e. stringification)
SV = PVIV(0x97e01b8) at 0x97df830
REFCNT = 1
FLAGS = (PADMY,IOK,POK,pIOK,pPOK)
IV = 8
PV = 0x97ee168 "8"\0
CUR = 1
LEN = 4
not 'eq'
$string_eight then $numeric_eight after all
SV = PV(0x98339d8) at 0x98736e8
REFCNT = 1
FLAGS = (PADMY,POK,pPOK)
PV = 0x97e4ba0 "8"\0
CUR = 1
LEN = 4
SV = PVIV(0x97e01b8) at 0x97df830
REFCNT = 1
FLAGS = (PADMY,IOK,POK,pIOK,pPOK)
IV = 8
PV = 0x97ee168 "8"\0
CUR = 1
LEN = 4
| [reply] [d/l] |
|
|
perl -MData::Dumper -wle'
my $r = { 010 => 123, 8 => 456 };
$r->{ 011 } = 789;
print Dumper $r;
'
$VAR1 = {
'8' => 456,
'9' => 789
};
| [reply] [d/l] |
Re: Illegal octal digit error
by CountZero (Bishop) on Jun 06, 2009 at 07:22 UTC
|
| [reply] [d/l] [select] |
Re: Illegal octal digit error
by afoken (Chancellor) on Jun 06, 2009 at 06:23 UTC
|
| [reply] |
Re: Illegal octal digit error
by Anonymous Monk on Jun 06, 2009 at 07:25 UTC
|
perl -Mdiagnostics -le"print for 08 => 1"
Illegal octal digit '8' at -e line 1, at end of line
Execution of -e aborted due to compilation errors (#1)
(F) You used an 8 or 9 in an octal number.
Uncaught exception from user code:
Illegal octal digit '8' at -e line 1, at end of line
Execution of -e aborted due to compilation errors.
at -e line 1
| [reply] [d/l] |