Video transcript & code
If you've watched episodes #194 and #195, you know that it's possible to use Ruby's string format features to convert numbers to just about any string representation we might want. But sometimes all we need is to convert a number to some non-decimal base, and using a string format seems like overkill.
You know, of course, that to convert a number to a string, we use the
#to_s method. What you might not be aware of is that this method takes an optional argument. If we pass the number 16, that means to convert the integer to a hexadecimal string representation. If we pass 8, we get an octal representation. And if we pass 2, we get binary.
42.to_s # => "42" 42.to_s(16) # => "2a" 42.to_s(8) # => "52" 42.to_s(2) # => "101010"
In fact, we can specify any base between 2 and 36. If for some reason we wanted to.
42.to_s(24) # => "1i" 42.to_s(36) # => "16"
Sometimes we want to go the other direction, and convert a non-decimal string to an integer. Again, Ruby has us covered. You're no doubt familiar with the
#to_i method. This method also takes an optional base.
"2A".to_i(16) # => 42 "101010".to_i(2) # => 42
You might recall from episode #207 that if we want a "strict" conversion from a string to an integer, we should prefer the
Integer() conversion function to the explicit conversion method. The
#to_i method will simply return 0 if it can't parse the string. Whereas the conversion function will convert valid numbers, but raises an exception for strings that can't be parsed as integers.
"a bajillion".to_i # => 0 Integer("42") # => 42 Integer("a bajillion") # => # ~> ArgumentError # ~> invalid value for Integer(): "a bajillion" # ~> # ~> xmptmp-in34032zZZ.rb:3:in `Integer' # ~> xmptmp-in34032zZZ.rb:3:in `<main>'
Integer() conversion function accepts an optional second argument specifying the expected base. If we specify base 16, it will accept numbers either with or without the traditional hexadecimal prefix of "0x".
Integer("2A", 16) # => 42 Integer("0x2A", 16) # => 42
What's really cool is that it will only allow this form when the base is 16. If we specify that we are looking for an octal number and pass in a string that starts with "0x", it will raise an exception.
Integer("0x2A", 8) # => # ~> ArgumentError # ~> invalid value for Integer(): "0x2A" # ~> # ~> xmptmp-in34032bHb.rb:1:in `Integer' # ~> xmptmp-in34032bHb.rb:1:in `<main>'
And that's how to easily convert integers to and from non-decimal string representations. I know it's not a ground-breaking feature, but it was a big time-saver for me when I finally discovered these optional arguments. Happy hacking!