Brooks Davis wrote:
> The behavior of sprintf("%d", str) is not what I would expect. If str
> begins with a '0', for example "01", it is treated as an octal number.
> This seem odd because I would expect the following two lines to be the
> same:
>
> sprintf("%d", str)
> sprintf("%d", str.to_i)
>
> This is not the case:
>
> irb(main):006:0> str="08"
> => "08"
> irb(main):007:0> sprintf("%d", str)
> ArgumentError: invalid value for Integer: "08"
> from (irb):7:in `sprintf'
> from (irb):7
> irb(main):008:0> sprintf("%d", str.to_i)
> => "8"
> irb(main):009:0> str="010"
> => "010"
> irb(main):010:0> sprintf("%d", str)
> => "8"
> irb(main):011:0> sprintf("%d", str.to_i)
> => "10"
>
> The seems to violate POLA. In my case it was quite astonishing because
> I had a script where I parse strings like "r01rpc2" to find the rack and
> power controller number from a string. When I added my eighth rack, the
> script stopped working after several years of operation. Is this
> behavior intended? The documentation on rubycentral doesn't really say
> one way or another.
>
This behavior is a little odd. The documentation for String#to_i (A bit
out of date here:
http://www.rubycentral.com/book/ref_c_string.html#String.to_i) says that
if no arg is passed to to_i(), then the default base is 10. The string
is then evaluated in that base, so leading 0's are ignored. If a base of
0 is given, then to_i() looks for leading '0', '0b', '0o', '0d', or '0x'
to determine the base. The method never raises an exception, but returns
0 instead when no valid number is found.
Thus:
irb(main):255:0> "08".to_i
=> 8
irb(main):256:0> "08".to_i(0) #Viewed as octal. '8' is invalid digit.
=> 0
irb(main):257:0> "07".to_i(0) #Octal
=> 7
irb(main):258:0> "7".to_i(0) #Decimal
=> 7
sprintf() appears to interpret numeric strings differently--in line with
the rules for numeric literals in Ruby:
irb(main):261:0> 08
SyntaxError: compile error
(irb):261: Illegal octal digit
from (irb):261
irb(main):262:0> sprintf("%d", "08")
ArgumentError: invalid value for Integer: "08"
from (irb):262:in `sprintf'
from (irb):262
irb(main):263:0> sprintf("%d", "0d8")
=> "8"
I would suggest you stick with explicitly calling to_i.
David Sletten