hex_dump строки

Время не стоит на месте, и в Crystal версии 0.26 уже есть прекрасный встроенный метод hexbytes для декодирования строки, содержащей шестнадцатеричный дамп, — в последовательность байт.

А как сделать прямое преобразование? То есть если у нас есть строка — и нужно получить её шестнадцатеричный дамп, какой метод можно использовать?

Ответ с одной стороны пока неутешителен: нет такого метода. С другой стороны, ответ слишком сложен, потому что на архитектуре Intel делать такое преобразование быстрее всего MMX-инструкциями, а значит — использовать встроенный asm-препроцессор (что, разумеется, не будет сделано разработчиками Crystal, поскольку они поддерживают «много разных архитектур» и стараются до последнего всё-таки обходиться собственными средствами языка).

Ну а с третьей стороны — как раз собственными средствами языка всё делается достаточно просто:

def hex_dump (s : String)
  s.to_slice.each_with_object(IO::Memory.new) {|b,s| s << b.to_s(16) }.to_s
end

Здесь мы сначала говорим: «с тем, что было строкой, далее работай как с указателем на побайтовый вектор» (s.to_slice), затем для каждого из байт, на которые указывает наш «слайс», вставляем их шестнадцатеричное представление в объект типа IO::Memory, созданный на лету в конструкции each_with_object. Само преобразование из «байта» в шестнадцатеричное строковое представление ('1' => 31) осуществляется функцией с наименее очевидной в данном случае семантикой: b.to_s(16).

Ну и в конце полученный объект типа IO::Memory преобразуется в строку (.to_s), после чего эта строка и становится выходным значением hex_dump'а

Кстати, это не самый эффективный способ преобразования: hex_dump(io) был бы и проще, и быстрее в случаях наподобие puts hex_dump(s). Но эту задачку я оставлю пытливым умам на домашнюю проработку :)

0 комментариев