103

In many languages there's a pair of functions, chr() and ord(), which convert between numbers and character values. In some languages, ord() is called asc().

Ruby has Integer#chr, which works great:

>> 65.chr
A

Fair enough. But how do you go the other way?

"A".each_byte do |byte|
   puts byte
end

prints:

65

and that's pretty close to what I want. But I'd really rather avoid a loop -- I'm looking for something short enough to be readable when declaring a const.

barelyknown
  • 5,510
  • 3
  • 34
  • 46
RJHunter
  • 2,829
  • 3
  • 25
  • 30

10 Answers10

84

If String#ord didn't exist in 1.9, it does in 2.0:

"A".ord #=> 65
Rob Cameron
  • 9,674
  • 7
  • 39
  • 42
33

In Ruby up to and including the 1.8 series, the following will both produce 65 (for ASCII):

puts ?A
'A'[0]

The behavior has changed in Ruby 1.9, both of the above will produce "A" instead. The correct way to do this in Ruby 1.9 is:

'A'[0].ord

Unfortunately, the ord method doesn't exist in Ruby 1.8.

Robert Gamble
  • 106,424
  • 25
  • 145
  • 137
  • It's unfortunate that the "correct" way in Ruby 1.9 is so long, but at least it'll show up easier in searches for "ord". Thanks for your very detailed answer. – RJHunter Nov 22 '08 at 11:30
13

Try:

'A'.unpack('c')
dylanfm
  • 6,292
  • 5
  • 28
  • 29
10

I'd like to +1 dylanfm and AShelly's comment but add the [0]:

'A'.unpack('C')[0]

The unpack call returns an Array containing a single integer, which is not always accepted where an integer is wanted:

$ ruby -e 'printf("0x%02X\n", "A".unpack("C"))'
-e:1:in `printf': can't convert Array into Integer (TypeError)
    from -e:1
$ ruby -e 'printf("0x%02X\n", "A".unpack("C")[0])'
0x41
$ 

I'm trying to write code that works on Ruby 1.8.1, 1.8.7 and 1.9.2.

Edited to pass C to unpack in uppercase, because unpack("c") gives me -1 where ord() gives me 255 (despite running on a platform where C's char is signed).

Martin Dorey
  • 2,944
  • 2
  • 24
  • 16
5

Just came across this while putting together a pure Ruby version of Stringprep via RFCs.

Beware that chr fails outside [0,255], instead use 1.9.x - 2.1.x portable replacements:

[22] pry(main)> "\u0221".ord.chr
RangeError: 545 out of char range
from (pry):2:in 'chr'
[23] pry(main)> x = "\u0221".unpack('U')[0]
=> 545
[24] pry(main)> [x].pack('U')
=> "ȡ"
[25] pry(main)>
  • 2
    Thank you, this seems to be the only answer that gives `char` and its inverse in the case of unicode correctly – Munyari Aug 13 '16 at 16:25
  • important context [here](https://bugs.ruby-lang.org/issues/17405) and [here](https://github.com/ruby/irb/issues/43) if anyone comes this way. – New Alexandria Sep 24 '22 at 21:00
3

Additionally, if you have the char in a string and you want to decode it without a loop:

puts 'Az'[0]
=> 65
puts 'Az'[1]
=> 122
Kent Fredric
  • 56,416
  • 14
  • 107
  • 150
2

You can have these:

65.chr.ord
'a'.ord.chr
Eduardo Santana
  • 5,780
  • 3
  • 19
  • 21
2

If you don't mind pulling the values out of an array, you can use "A".bytes

Clark
  • 416
  • 3
  • 10
2

How about

puts ?A

GregD
  • 6,860
  • 5
  • 34
  • 61
0

I'm writing code for 1.8.6 and 1.9.3 and I couldn't get any of these solutions to work in both environments :(

However, I came across another solution: http://smajnr.net/2009/12/ruby-1-8-nomethoderror-undefined-method-ord-for-string.html

That didn't work for me either but I adapted it for my use:

unless "".respond_to?(:ord)
  class Fixnum
    def ord
      return self
    end
  end
end

Having done that, then the following will work in both environments

'A'[0].ord
  • When user18096 wrote their answer, `"A".unpack("C")[0]`, that was targeting Ruby 1.8.1, Ruby 1.8.7 and Ruby 1.9.2. Does it fail in your environment? What kind of failure? – RJHunter Apr 13 '15 at 22:32
  • Hi RJHunter, I am trying to convert a specific character in a string to its number value. The following code works in 1.9.3 but not 1.8.6. `self.status = tagAccountString[4].unpack('C')[0]` In 1.8.6 I get `Exception undefined method `unpack' for 0:Fixnum processing main buffered tag data - exit` The following code works (with my proposed solution) in both environments `self.status = tagAccountString[4].ord` Any advice (e.g. a better solution) is more than welcome – hantscolin Apr 15 '15 at 10:19
  • `tagAccountString[4]` returns a String in newer Rubies but used to return a Fixnum in Ruby 1.8. That's why you saw the error, `undefined method unpack for 0:Fixnum`. You could use `status = tagAccountString[4,1].unpack('C')[0]` or even `status, = tagAccountString.unpack('xxxxC')` if you always want to ignore four characters and convert the next one. – RJHunter Apr 18 '15 at 05:25
  • Thanks RJHunter for the explanation and alternative solutions. However, as "my" solution is more readable and reusable, I'll stick with that (unless there is a good reason not too?) – hantscolin Apr 22 '15 at 13:34