Quel est le contraire de chr () dans Ruby?


100

Dans de nombreuses langues, il existe une paire de fonctions, chr()et ord(), qui convertissent entre les nombres et les valeurs de caractères. Dans certaines langues, ord()est appelé asc().

Ruby a Integer#chr, ce qui fonctionne très bien:

>> 65.chr
A

C'est suffisant. Mais comment allez-vous dans l'autre sens?

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

imprime:

65

et c'est assez proche de ce que je veux. Mais je préfère vraiment éviter une boucle - je recherche quelque chose d'assez court pour être lisible lors de la déclaration d'un fichier const.

Réponses:


84

Si String # ord n'existait pas dans la version 1.9, c'est le cas dans la version 2.0:

"A".ord #=> 65

33

Dans Ruby jusqu'à et y compris la série 1.8, les éléments suivants en produiront tous deux 65 (pour ASCII):

puts ?A
'A'[0]

Le comportement a changé dans Ruby 1.9, les deux éléments ci-dessus produiront "A" à la place. La bonne façon de faire cela dans Ruby 1.9 est:

'A'[0].ord

Malheureusement, la ordméthode n'existe pas dans Ruby 1.8.


Il est malheureux que la méthode "correcte" dans Ruby 1.9 soit si longue, mais au moins elle apparaîtra plus facilement dans les recherches de "ord". Merci pour votre réponse très détaillée.
RJHunter

13

Essayer:

'A'.unpack('c')

1
Maintenant que Ruby 1.9 a changé la signification de «A» [0], c'est la méthode la plus portable.
AShelly

10

J'aimerais attribuer +1 au commentaire de dylanfm et AShelly mais ajouter le [0]:

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

L'appel unpack renvoie un tableau contenant un seul entier, ce qui n'est pas toujours accepté là où un entier est souhaité:

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

J'essaye d'écrire du code qui fonctionne sur Ruby 1.8.1, 1.8.7 et 1.9.2.

Édité pour passer C pour décompresser en majuscules, car unpack ("c") me donne -1 où ord () me donne 255 (malgré l'exécution sur une plate-forme où le caractère de C est signé).


4

Je viens de tomber sur cela lors de la création d'une version Ruby pure de Stringprep via RFC.

Attention qui chréchoue en dehors de [0,255], utilisez plutôt des remplacements portables 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)>

Merci, cela semble être la seule réponse qui donne charet son inverse dans le cas d'unicode correctement
Munyari

3

De plus, si vous avez le char dans une chaîne et que vous souhaitez le décoder sans boucle:

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



2

Si cela ne vous dérange pas d'extraire les valeurs d'un tableau, vous pouvez utiliser "A".bytes


0

J'écris du code pour 1.8.6 et 1.9.3 et je n'ai pas réussi à faire fonctionner l'une de ces solutions dans les deux environnements :(

Cependant, je suis tombé sur une autre solution: http://smajnr.net/2009/12/ruby-1-8-nomethoderror-undefined-method-ord-for-string.html

Cela n'a pas fonctionné pour moi non plus mais je l'ai adapté à mon usage:

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

Après avoir fait cela, alors ce qui suit fonctionnera dans les deux environnements

'A'[0].ord


Lorsque user18096 a écrit sa réponse, "A".unpack("C")[0]cela ciblait Ruby 1.8.1, Ruby 1.8.7 et Ruby 1.9.2. Cela échoue-t-il dans votre environnement? Quel genre d'échec?
RJHunter

Salut RJHunter, j'essaie de convertir un caractère spécifique dans une chaîne en sa valeur numérique. Le code suivant fonctionne dans 1.9.3 mais pas 1.8.6. self.status = tagAccountString[4].unpack('C')[0] Dans la version 1.8.6, je reçois Exception undefined method unpack 'for 0: Fixnum traitant les données des balises tamponnées principales - exit` Le code suivant fonctionne (avec ma solution proposée) dans les deux environnements. self.status = tagAccountString[4].ord Tout conseil (par exemple, une meilleure solution) est plus que bienvenu
hantscolin

tagAccountString[4]renvoie une chaîne dans les Rubis plus récents mais utilisée pour renvoyer un Fixnum dans Ruby 1.8. Voilà pourquoi vous avez vu l'erreur, undefined method unpack for 0:Fixnum. Vous pouvez utiliser status = tagAccountString[4,1].unpack('C')[0]ou même status, = tagAccountString.unpack('xxxxC')si vous voulez toujours ignorer quatre caractères et convertir le suivant.
RJHunter

Merci RJHunter pour l'explication et les solutions alternatives. Cependant, comme "ma" solution est plus lisible et réutilisable, je m'en tiendrai à ça (à moins qu'il n'y ait une bonne raison pas trop?)
hantscolin
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.