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.

Jawaban:



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.


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

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


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

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



2

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


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


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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.