Jakie jest przeciwieństwo chr () w Rubim?

100

W wielu językach istnieje para funkcji chr()i ord(), które konwertują liczby i wartości znakowe. W niektórych językach ord()nazywa się asc().

Ruby ma Integer#chr, co działa świetnie:

>> 65.chr
A

Słusznie. Ale jak idziesz w drugą stronę?

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

wydruki:

65

i to jest bardzo bliskie temu, czego chcę. Ale naprawdę wolałbym uniknąć pętli - szukam czegoś wystarczająco krótkiego, aby był czytelny podczas deklarowania pliku const.

RJHunter
źródło

Odpowiedzi:

84

Jeśli String # ord nie istniał w 1.9, to w 2.0:

"A".ord #=> 65
Rob Cameron
źródło
33

W Rubim do serii 1.8 włącznie, oba poniższe wygenerują 65 (dla ASCII):

puts ?A
'A'[0]

Zachowanie zmieniło się w Rubim 1.9, oba powyższe spowodują zamiast tego "A". Poprawny sposób na zrobienie tego w Rubim 1.9 to:

'A'[0].ord

Niestety, ordmetoda ta nie istnieje w Rubim 1.8.

Robert Gamble
źródło
Szkoda, że ​​„poprawna” droga w Rubim 1.9 jest tak długa, ale przynajmniej będzie łatwiejsza w wynikach wyszukiwania hasła „ord”. Dziękuję za bardzo szczegółową odpowiedź.
RJHunter
13

Próbować:

'A'.unpack('c')
dylanfm
źródło
1
Teraz, gdy Ruby 1.9 zmienił znaczenie „A” [0], jest to bardziej przenośna metoda.
AShelly
10

Chciałbym dać +1 komentarzowi dylanfm i AShelly, ale dodaję [0]:

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

Wywołanie unpack zwraca tablicę zawierającą pojedynczą liczbę całkowitą, która nie zawsze jest akceptowana, gdy potrzebna jest liczba całkowita:

$ ruby ​​-e 'printf ("0x% 02X \ n", "A" .unpack ("C"))'
-e: 1: w `printf ': nie można przekonwertować tablicy na liczbę całkowitą (TypeError)
    od -e: 1
$ ruby ​​-e 'printf ("0x% 02X \ n", "A" .unpack ("C") [0])'
0x41
$ 

Próbuję napisać kod, który działa na Rubim 1.8.1, 1.8.7 i 1.9.2.

Edytowane, aby przekazać C do rozpakowywania wielkimi literami, ponieważ unpack ("c") daje mi -1, gdzie ord () daje mi 255 (pomimo uruchomienia na platformie, na której znak C jest podpisany).

Martin Dorey
źródło
4

Właśnie natknąłem się na to podczas tworzenia czystego Ruby w wersji Stringprep przez RFC.

Uważaj, że chrnie działa poza [0,255], zamiast tego użyj przenośnych zamienników 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)>

źródło
Dziękuję, wydaje się, że jest to jedyna odpowiedź, która daje chari jej odwrotność w przypadku
unicodu
3

Dodatkowo, jeśli masz znak w ciągu i chcesz go zdekodować bez pętli:

puts 'Az'[0]
=> 65
puts 'Az'[1]
=> 122
Kent Fredric
źródło
2

Możesz mieć te:

65.chr.ord
'a'.ord.chr
Eduardo Santana
źródło
2

Jeśli nie masz nic przeciwko wyciągnięciu wartości z tablicy, możesz użyć "A".bytes

Clark
źródło
0

Piszę kod dla 1.8.6 i 1.9.3 i nie udało mi się uzyskać żadnego z tych rozwiązań do pracy w obu środowiskach :(

Natrafiłem jednak na inne rozwiązanie: http://smajnr.net/2009/12/ruby-1-8-nomethoderror-undefined-method-ord-for-string.html

To też nie zadziałało, ale dostosowałem go do swojego użytku:

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

Po wykonaniu tej czynności poniższe będą działać w obu środowiskach

'A'[0].ord

hantscolin
źródło
Kiedy użytkownik18096 napisał swoją odpowiedź, "A".unpack("C")[0]był to cel dla Ruby 1.8.1, Ruby 1.8.7 i Ruby 1.9.2. Czy zawodzi w Twoim środowisku? Jaki rodzaj awarii?
RJHunter
Cześć RJHunter, Próbuję przekonwertować określony znak w ciągu na jego wartość liczbową. Poniższy kod działa w wersji 1.9.3, ale nie w wersji 1.8.6. self.status = tagAccountString[4].unpack('C')[0] W 1.8.6 dostaję Exception undefined method unpack 'for 0: Fixnum przetwarza główne buforowane dane tagu - wyjście` Poniższy kod działa (z moim proponowanym rozwiązaniem) w obu środowiskach self.status = tagAccountString[4].ord Każda rada (np. Lepsze rozwiązanie) jest więcej niż mile widziana
hantscolin
tagAccountString[4]zwraca String w nowszych Rubinach, ale używany do zwracania Fixnum w Rubim 1.8. Dlatego ten błąd undefined method unpack for 0:Fixnum. Możesz użyć status = tagAccountString[4,1].unpack('C')[0]lub nawet status, = tagAccountString.unpack('xxxxC')jeśli zawsze chcesz zignorować cztery znaki i przekonwertować następny.
RJHunter
Dzięki RJHunter za wyjaśnienie i alternatywne rozwiązania. Ponieważ jednak „moje” rozwiązanie jest bardziej czytelne i nadaje się do wielokrotnego użytku, będę się tego trzymać (chyba, że ​​jest dobry powód, nie?)
hantscolin