При отладке программ, которые работают с бинарными данными, часто нужно вывести содержимое строки на экран, причём желательно в виде шестнадцатеричной строки.
Для этого можно использовать следующую небольшую функцию hex
.
local function hex(s)
return s:gsub(".", function(c)
return ("%02x "):format(c:byte())
end):sub(1, -2)
end
print(hex("\x01\x23\x45\x67\x89\xab\xcd\xef"))
--> 01 23 45 67 89 ab cd ef
Чтобы понять, как оно работает, нужно понимать, что для всех строк установлена
метатаблица с полем __index
, ссылающееся на string
. Таким образом, для
строки s
запись s.sub(s, 1, 2)
эквивалентна string.sub(s, 1, 2)
.
Так как первым аргументом метода строки передаётся сама строка, то можно
сократить s.sub(s, 1, 2)
до s:sub(1, 2)
.
Строковые литералы (строк, записанных прямо в коде, вроде "hey"
) также
являются строками, поэтому у них также можно вызвать функции string
. Однако
напрямую индексировать литерал (в смысле, писать "test":sub(1, 2)
) нельзя —
это будет синтаксической ошибкой. Литерал нужно обернуть в скобки:
("test"):sub(1, 2)
— эквивалентно string.sub("test", 1, 2)
, но короче.
Мы используем функцию string.gsub
, передав шаблон "."
(любой символ) и
функцию. Функция будет вызываться для каждого символа и менять его на то,
что она вернёт.
С помощью string.byte
(c:byte()
) мы получаем числовое значение байта. Затем
передаём его в string.format
с форматом "%02x "
. %x
конвертирует число в
шестнадцатеричное, %02x
также дополняет число слева нулямм до тех пор, пока
длина его не будет равна двум (число 14
превращает в 0e
, например). После
каждого символа добавляем пробел.
Наконец, убираем в конце лишний пробел после последнего символа с помощью
string.sub
и возвращаем полученную строку.