Qual è il contrario di chr () in Ruby?


100

In molte lingue ci sono un paio di funzioni, chr()e ord(), che convertono tra numeri e valori di carattere. In alcune lingue, ord()si chiama asc().

Ruby ha Integer#chr, che funziona benissimo:

>> 65.chr
A

Giusto. Ma come fai ad andare dall'altra parte?

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

stampe:

65

e questo è abbastanza vicino a quello che voglio. Ma preferirei davvero evitare un ciclo: sto cercando qualcosa di abbastanza breve da essere leggibile quando dichiaro un file const.

Risposte:


84

Se String # ord non esisteva nella 1.9, lo è nella 2.0:

"A".ord #=> 65

33

In Ruby fino alla serie 1.8 inclusa, quanto segue produrrà entrambi 65 (per ASCII):

puts ?A
'A'[0]

Il comportamento è cambiato in Ruby 1.9, entrambi i precedenti produrranno invece "A". Il modo corretto per farlo in Ruby 1.9 è:

'A'[0].ord

Sfortunatamente, il ordmetodo non esiste in Ruby 1.8.


È un peccato che il modo "corretto" in Ruby 1.9 sia così lungo, ma almeno risulterà più facile nelle ricerche per "ord". Grazie per la tua risposta molto dettagliata.
— RJHunter

13

Provare:

'A'.unpack('c')

1
Ora che Ruby 1.9 ha cambiato il significato di "A" [0], questo è il metodo più portabile.
— AShelly,

10

Vorrei fare +1 sul commento di dylanfm e AShelly ma aggiungere lo [0]:

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

La chiamata unpack restituisce un Array contenente un singolo intero, che non è sempre accettato dove si desidera un intero:

$ ruby ​​-e 'printf ("0x% 02X \ n", "A" .unpack ("C"))'
-e: 1: in `printf ': impossibile convertire Array in Integer (TypeError)
    da -e: 1
$ ruby ​​-e 'printf ("0x% 02X \ n", "A" .unpack ("C") [0])'
0x41
$ 

Sto cercando di scrivere codice che funzioni su Ruby 1.8.1, 1.8.7 e 1.9.2.

Modificato per passare C per decomprimere in maiuscolo, perché unpack ("c") mi dà -1 dove ord () mi dà 255 (nonostante sia in esecuzione su una piattaforma in cui il carattere di C è firmato).


4

Mi sono appena imbattuto in questo mentre metti insieme una versione Ruby pura di Stringprep tramite RFC.

Attenzione che chrfallisce al di fuori di [0,255], usa invece 1.9.x - 2.1.x sostituzioni portatili:

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

Grazie, questa sembra essere l'unica risposta che dà chare il suo inverso nel caso dell'unicode correttamente
— Munyari

3

Inoltre, se hai il carattere in una stringa e vuoi decodificarlo senza un ciclo:

puts 'Az'[0]
=> 65
puts 'Az'[1]
=> 122



2

Se non ti dispiace estrarre i valori da un array, puoi usare "A".bytes


0

Sto scrivendo codice per 1.8.6 e 1.9.3 e non sono riuscito a far funzionare nessuna di queste soluzioni in entrambi gli ambienti :(

Tuttavia, mi sono imbattuto in un'altra soluzione: http://smajnr.net/2009/12/ruby-1-8-nomethoderror-undefined-method-ord-for-string.html

Anche questo non ha funzionato per me, ma l'ho adattato per il mio uso:

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

Fatto ciò, quanto segue funzionerà in entrambi gli ambienti

'A'[0].ord


Quando user18096 ha scritto la risposta, "A".unpack("C")[0]era indirizzata a Ruby 1.8.1, Ruby 1.8.7 e Ruby 1.9.2. Non funziona nel tuo ambiente? Che tipo di fallimento?
— RJHunter

Ciao RJHunter, sto cercando di convertire un carattere specifico in una stringa nel suo valore numerico. Il codice seguente funziona in 1.9.3 ma non 1.8.6. self.status = tagAccountString[4].unpack('C')[0] In 1.8.6 ottengo Exception undefined method unpack 'for 0: Fixnum processing main buffered tag data - exit` Il codice seguente funziona (con la mia soluzione proposta) in entrambi gli ambienti self.status = tagAccountString[4].ord Qualsiasi consiglio (ad esempio una soluzione migliore) è più che benvenuto
— hantscolin

tagAccountString[4]restituisce una stringa nella versione più recente di Ruby ma utilizzata per restituire un Fixnum in Ruby 1.8. È per questo che hai visto l'errore, undefined method unpack for 0:Fixnum. Puoi usare status = tagAccountString[4,1].unpack('C')[0]o anche status, = tagAccountString.unpack('xxxxC')se vuoi sempre ignorare quattro caratteri e convertire quello successivo.
— RJHunter

Grazie RJHunter per la spiegazione e le soluzioni alternative. Tuttavia, poiché la "mia" soluzione è più leggibile e riutilizzabile, continuerò con quella (a meno che non ci sia una buona ragione per non farlo anch'io?)
— hantscolin
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.