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

Respuestas:



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.


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

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


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

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



2

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


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


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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.