Apa kebalikan dari chr () di Ruby?

100

Dalam banyak bahasa terdapat sepasang fungsi, chr()dan ord(), yang mengonversi antara angka dan nilai karakter. Dalam beberapa bahasa, ord()disebut asc().

Ruby punya Integer#chr, yang berfungsi dengan baik:

>> 65.chr
A

Cukup adil. Tapi bagaimana Anda pergi ke arah lain?

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

cetakan:

65

dan itu cukup dekat dengan apa yang saya inginkan. Tetapi saya benar-benar lebih suka menghindari loop - Saya mencari sesuatu yang cukup pendek agar dapat dibaca saat mendeklarasikan file const.

RJHunter
sumber

Jawaban:

84

Jika String # ord tidak ada di 1.9, itu ada di 2.0:

"A".ord #=> 65
Rob Cameron
sumber
33

Di Ruby hingga dan termasuk seri 1.8, berikut ini akan menghasilkan 65 (untuk ASCII):

puts ?A
'A'[0]

Perilaku telah berubah di Ruby 1.9, kedua cara di atas akan menghasilkan "A" sebagai gantinya. Cara yang benar untuk melakukannya di Ruby 1.9 adalah:

'A'[0].ord

Sayangnya, ordmetode ini tidak ada di Ruby 1.8.

Robert Gamble
sumber
Sayangnya cara yang "benar" di Ruby 1.9 sangat panjang, tapi setidaknya cara itu akan lebih mudah muncul dalam pencarian untuk "ord". Terima kasih atas jawaban Anda yang sangat mendetail.
RJHunter
13

Mencoba:

'A'.unpack('c')
dylanfm.dll
sumber
1
Sekarang Ruby 1.9 telah mengubah arti 'A' [0], ini adalah metode yang lebih portabel.
AShelly
10

Saya ingin memberi +1 pada komentar dylanfm dan AShelly, tetapi tambahkan [0]:

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

Panggilan unpack mengembalikan Array yang berisi integer tunggal, yang tidak selalu diterima di mana integer diinginkan:

$ ruby ​​-e 'printf ("0x% 02X \ n", "A" .unpack ("C"))'
-e: 1: di `printf ': tidak dapat mengubah Array menjadi Integer (TypeError)
    dari -e: 1
$ ruby ​​-e 'printf ("0x% 02X \ n", "A" .unpack ("C") [0])'
0x41
$ 

Saya mencoba menulis kode yang berfungsi di Ruby 1.8.1, 1.8.7 dan 1.9.2.

Diedit untuk meneruskan C untuk membongkar dalam huruf besar, karena membongkar ("c") memberi saya -1 di mana ord () memberi saya 255 (meskipun berjalan pada platform di mana karakter C ditandatangani).

Martin Dorey
sumber
4

Baru saja menemukan ini saat menyusun versi Ruby murni dari Stringprep melalui RFC.

Hati-hati jika chrgagal di luar [0,255], gunakan pengganti portabel 1.9.x - 2.1.x:

[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)>

sumber
Terima kasih, ini tampaknya menjadi satu-satunya jawaban yang memberi chardan kebalikannya dalam kasus unicode yang benar
Munyari
3

Selain itu, jika Anda memiliki karakter dalam string dan Anda ingin mendekodekannya tanpa loop:

puts 'Az'[0]
=> 65
puts 'Az'[1]
=> 122
Kent Fredric
sumber
2

Bagaimana tentang

menempatkan?

GregD
sumber
2

Anda dapat memiliki ini:

65.chr.ord
'a'.ord.chr
Eduardo Santana
sumber
2

Jika Anda tidak keberatan mengeluarkan nilai dari array, Anda dapat menggunakan "A".bytes

Clark
sumber
0

Saya menulis kode untuk 1.8.6 dan 1.9.3 dan saya tidak bisa mendapatkan solusi ini untuk bekerja di kedua lingkungan :(

Namun, saya menemukan solusi lain: http://smajnr.net/2009/12/ruby-1-8-nomethoderror-undefined-method-ord-for-string.html

Itu juga tidak berhasil untuk saya tetapi saya menyesuaikannya untuk saya gunakan:

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

Setelah melakukan itu, maka yang berikut ini akan berfungsi di kedua lingkungan

'A'[0].ord

hantscolin
sumber
Ketika user18096 menulis jawaban mereka, "A".unpack("C")[0]itu menargetkan Ruby 1.8.1, Ruby 1.8.7 dan Ruby 1.9.2. Apakah itu gagal di lingkungan Anda? Kegagalan macam apa?
RJHunter
Hai RJHunter, Saya mencoba untuk mengubah karakter tertentu dalam string menjadi nilai angka. Kode berikut berfungsi di 1.9.3 tetapi tidak di 1.8.6. self.status = tagAccountString[4].unpack('C')[0] Di 1.8.6 saya mendapatkan Exception undefined method unpack 'for 0: Fixnum memproses data tag buffered utama - exit` Kode berikut berfungsi (dengan solusi yang saya usulkan) di kedua lingkungan. self.status = tagAccountString[4].ord Setiap saran (misalnya solusi yang lebih baik) lebih dari diterima
hantscolin
tagAccountString[4]mengembalikan String di Rubi yang lebih baru tetapi digunakan untuk mengembalikan Fixnum di Ruby 1.8. Itulah mengapa Anda melihat kesalahan undefined method unpack for 0:Fixnum,. Anda dapat menggunakan status = tagAccountString[4,1].unpack('C')[0]atau bahkan status, = tagAccountString.unpack('xxxxC')jika Anda selalu ingin mengabaikan empat karakter dan mengonversi yang berikutnya.
RJHunter
Terima kasih RJHunter atas penjelasan dan alternatif solusinya. Namun, karena solusi "saya" lebih mudah dibaca dan digunakan kembali, saya akan tetap menggunakannya (kecuali jika ada alasan bagus untuk tidak juga?)
hantscolin