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.