From: David Sletten Date: 2005-01-27T11:25:56+09:00 Subject: Re: printf with octal numbers 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