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.

RJHunter
la source

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
Rob Cameron
la source
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.

Robert Gamble
la source
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')
dylanfm
la source
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é).

Martin Dorey
la source
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)>

la source
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
Kent Fredric
la source
2

Vous pouvez avoir ceux-ci:

65.chr.ord
'a'.ord.chr
Eduardo Santana
la source
2

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

Clark
la source
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

hantscolin
la source
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