¿Qué es lo opuesto a chr () en Ruby?

100

En muchos idiomas hay un par de funciones, chr()y ord(), que convierten entre números y valores de caracteres. En algunos idiomas, ord()se llama asc().

Ruby tiene Integer#chr, que funciona muy bien:

>> 65.chr
A

Lo suficientemente justo. Pero, ¿cómo vas al otro lado?

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

huellas dactilares:

65

y eso se acerca bastante a lo que quiero. Pero realmente prefiero evitar un bucle: estoy buscando algo lo suficientemente corto como para que sea legible al declarar un const.

RJHunter
fuente

Respuestas:

84

Si String # ord no existía en 1.9, sí en 2.0:

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

En Ruby hasta la serie 1.8 incluida, lo siguiente producirá 65 (para ASCII):

puts ?A
'A'[0]

El comportamiento ha cambiado en Ruby 1.9, los dos anteriores producirán "A" en su lugar. La forma correcta de hacer esto en Ruby 1.9 es:

'A'[0].ord

Desafortunadamente, el ordmétodo no existe en Ruby 1.8.

Robert Gamble
fuente
Es lamentable que la forma "correcta" en Ruby 1.9 sea tan larga, pero al menos aparecerá más fácilmente en las búsquedas de "ord". Gracias por tu respuesta tan detallada.
RJHunter
13

Tratar:

'A'.unpack('c')
Dylanfm
fuente
1
Ahora que Ruby 1.9 ha cambiado el significado de 'A' [0], este es el método más portátil.
AShelly
10

Me gustaría hacer +1 en dylanfm y en el comentario de AShelly, pero agregar el [0]:

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

La llamada al desempaquetado devuelve una matriz que contiene un solo entero, que no siempre se acepta cuando se desea un entero:

$ ruby ​​-e 'printf ("0x% 02X \ n", "A" .unpack ("C"))'
-e: 1: en `printf ': no ​​se puede convertir Array en Integer (TypeError)
    desde -e: 1
$ ruby ​​-e 'printf ("0x% 02X \ n", "A" .unpack ("C") [0])'
0x41
PS 

Estoy intentando escribir código que funcione en Ruby 1.8.1, 1.8.7 y 1.9.2.

Editado para pasar C para descomprimir en mayúsculas, porque desempaquetar ("c") me da -1 donde ord () me da 255 (a pesar de ejecutarse en una plataforma donde el carácter de C está firmado).

Martin Dorey
fuente
4

Me encontré con esto mientras preparaba una versión Ruby pura de Stringprep a través de RFC.

Tenga en cuenta que chrfalla fuera de [0,255], en su lugar use reemplazos portátiles 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)>

fuente
Gracias, esta parece ser la única respuesta que da chary su inversa en el caso de Unicode correctamente
Munyari
3

Además, si tiene el carácter en una cadena y desea decodificarlo sin un bucle:

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

Qué tal si

pone?

GregD
fuente
2

Puedes tener estos:

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

Si no le importa sacar los valores de una matriz, puede usar "A".bytes

Clark
fuente
0

Estoy escribiendo código para 1.8.6 y 1.9.3 y no pude hacer que ninguna de estas soluciones funcione en ambos entornos :(

Sin embargo, encontré otra solución: http://smajnr.net/2009/12/ruby-1-8-nomethoderror-undefined-method-ord-for-string.html

Eso tampoco funcionó para mí, pero lo adapté para mi uso:

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

Una vez hecho esto, lo siguiente funcionará en ambos entornos.

'A'[0].ord

hantscolin
fuente
Cuando el usuario 18096 escribió su respuesta, "A".unpack("C")[0]estaba dirigida a Ruby 1.8.1, Ruby 1.8.7 y Ruby 1.9.2. ¿Falla en su entorno? ¿Qué tipo de fracaso?
RJHunter
Hola RJHunter, estoy tratando de convertir un carácter específico en una cadena a su valor numérico. El siguiente código funciona en 1.9.3 pero no 1.8.6. self.status = tagAccountString[4].unpack('C')[0] En 1.8.6 obtengo Exception undefined method desempaquetar 'para 0: Fixnum procesando datos de la etiqueta principal en búfer - salir' El siguiente código funciona (con mi solución propuesta) en ambos entornos self.status = tagAccountString[4].ord Cualquier consejo (por ejemplo, una mejor solución) es más que bienvenido
hantscolin
tagAccountString[4]devuelve un String en Rubies más nuevos pero se usa para devolver un Fixnum en Ruby 1.8. Por eso vio el error undefined method unpack for 0:Fixnum. Puede usar status = tagAccountString[4,1].unpack('C')[0]o incluso status, = tagAccountString.unpack('xxxxC')si siempre desea ignorar cuatro caracteres y convertir el siguiente.
RJHunter
Gracias RJHunter por la explicación y las soluciones alternativas. Sin embargo, como "mi" solución es más legible y reutilizable, me quedaré con eso (a menos que haya una buena razón para no hacerlo también)
hantscolin