2014-02-14 3 views
2

Моя программа является декодером для двоичного протокола. Одним из полей в этом двоичном протоколе является кодированный String. Каждый символ в String можно распечатать и представляет собой целочисленное значение. В соответствии со спецификацией протокола я декодирования, интегральная величина представляет берется из следующей таблицы, где перечислены все возможные символы:Rubyist способ декодировать эту закодированную строку, предполагая инвариантную кодировку ASCII

Character Value 
========= ===== 
0   0 
1   1 
2   2 
3   3 
    [...] 
:   10 
;   11 
<   12 
=   13 
    [...] 
B   18 

Так, например, характер = представляет собой составную 13.

Мой код был первоначально используя ord, чтобы получить код ASCII для символа, а затем вычитая 48 от того, как это:

def Decode(val) 
    val[0].ord - 48 
end 

... который прекрасно работает, если предположить, что val состоит только из символов перечисленные в этой таблице (это проверено в другом месте).

Однако в another question, мне сказали, что:

Вы просите способ Руби использовать Ord, где его использование против путь рубин.

Мне кажется, что ord это именно то, что мне нужно, поэтому я не понимаю, почему использование ord здесь не Rubyist способ сделать то, что я пытаюсь сделать.

Так что мои вопросы:

Прежде всего, что такое Rubyist способ написать свою функцию выше? Secondary, Почему использует ord здесь нерубистская практика?

Замечание о кодировании: этот протокол, который я декодирует, точно определяет, что эти строки закодированы в ASCII. Здесь нет никакой другой кодировки. Подобные протоколы чрезвычайно распространены в моей отрасли (товарные рынки &).

+0

Я вижу. Код, относящийся к логике низкого уровня, возможно, должен использовать 'ord', но он не может быть частью Rubyistic кода. Это должна быть уродливая часть кода, которая должна быть скрыта в каталоге как оболочка/адаптер для вызова из основной логики в отдельном файле. Кстати, интеграл? Вероятно, вы имеете в виду целое число. – sawa

+3

Если спецификация гарантирует, что строки всегда будут ASCII, вы можете использовать 'ord', без проблем. Почему это «не-рубиновый путь» - я не могу сказать. :) –

+0

Цель всего кода была не ясна из информации, приведенной в вопросе, в то время, когда я прокомментировал. Было похоже, что OP просто пытался извлечь числа из строки, используя 'ord' вместо' to_i'. – sawa

ответ

4

Я угадать Rubyistic пути, и быстрее, чтобы декодировать строку в массив целых чисел является unpack метода:

"=01:".unpack("C*").map {|v| v - 48} 
>> [13, 0, 1, 10] 

unpack метод, с "C*" парами, преобразует каждый символ в 8-битном unsigned integer.

+0

+1: Я использую 'unpack' * extensively * через свой код, но я не понимал, что он может сделать это напрямую. На самом деле я не думал перерабатывать вывод 'unpack' с' map'. –

+0

Однако меня удивляет, что вы утверждаете, что это будет быстрее. –

+0

Я предполагаю, что это быстрее, потому что метод 'unpack' полностью реализован в коде C. –

1

Возможно, ord абсолютно безопасен и уместен в вашем случае, так как исходные данные должны всегда кодироваться одинаково. Особенно, если при чтении данных вы устанавливаете кодировку на 'US-ASCII' (хотя используемый формат выглядит безопасно для «ASCII-8BIT», «UTF-8» и «ISO-8859», что может быть его точкой), кажется, много преобразований и не использует все возможные байтовые значения). Однако ord - это , предназначенный для использования с семантикой символов, и технически вы хотите использовать семантику байта. С основными ASCII и вариантами нет практической разницы, все байтовые значения ниже 128 - это один и тот же код символа.

Я бы предложил использовать String#unpack в качестве общего метода преобразования двоичного ввода в типы данных Ruby, но не существует кода unpack для «использования этого байта со смещением», так что это станет двухчастным процессом.

Смежные вопросы