Преобразование шестнадцатеричной строки в целое число с помощью python
Обратите внимание, что задача состоит не из шестнадцатеричного к десятичному, а из строки шестнадцатеричных значений к целому числу.
Скажем, у меня есть жало от шестигранника (например. '6c 02 00 00'), поэтому мне нужно сначала преобразовать его в фактический шестнадцатеричный код, а затем получить целое число, которое он представляет... (этот конкретный будет 620 как int16 и int32)
Я перепробовал много вещей, но запутался еще больше. Есть ли быстрый способ сделать такое преобразование в python (желательно 3.х)?
2 ответов:
Не только это строка, но она находится в маленьком конечном порядке - meanng, что просто удаление пробелов и использование вызова
int(xx, 16)будет работать. Кроме того, он не имеет фактических байтовых значений в виде 4 произвольных чисел 0-255 (в этом случае struct.распаковать бы получилось).Я думаю, что хороший подход состоит в том, чтобы поменять компоненты обратно в" читаемый человеком " порядок и использовать вызов int-таким образом:
number = int("".join("6c 02 00 00".split()[::-1]), 16)Что там происходит: первая часть Th expession - это
split- она разрывает строку на пробелов, и предоставляет список с четырьмя строками, по две цифры в каждой. Специальный срез [:: -1] идет следующим - это примерно означает "предоставьте мне подмножество элементов из предыдущей последовательности, начиная с краев и возвращаясь по 1 элементу за раз" - что является общей идиомой Python для обращения любой последовательности.Эта обратная последовательность используется в вызове
"".join(...), который в основном использует пустую строку в качестве конкатенатора для каждого элемента в последовательности-результатом этого вызова является "0000026c". С этим значением мы просто вызываем класс Pythonint, который принимает вторичный необязательный параметр, обозначающий основание, которое должно использоваться для интерпретации числа, обозначенного в первом аргументе.>>> int("".join("6c 02 00 00".split()[::-1]), 16) 620Другой вариант-суммировать преобразование каждых 2 цифр, правильно сдвинутых к их весу в соответствии с их положением - это также может быть сделано в одном выражении с использованием
reduce, хотя 4-строчный цикл Pythonforбыл бы больше читаем:>>> from functools import reduce #not needed in Python2.x >>> reduce(lambda x, y: x + (int(y[1], 16)<<(8 * y[0]) ), enumerate("6c 02 00 00".split()), 0) 620Update ОП просто сказал, что у него на самом деле нет "пробелов" в строке - в этом случае можно использовать просто те же методы, но беря каждые две цифры вместо вызова
split():reduce(lambda x, y: x + (int(y[1], 16)<<(8 * y[0]//2) ), ((i, a[i:i+2]) for i in range(0, len(a), 2)) , 0)(где
a- переменная с вашими цифрами, конечно) - Или преобразуйте его в фактическое 4-байтовое число в памяти, подпишите шестнадцатеричный кодек и распакуйте число с помощью struct - это может быть более семантически корректно для вашего кода:import codecs import struct struct.unpack("<I", codecs.decode("6c020000", "hex") )[0]Итак подход здесь состоит в том, чтобы передать каждые 2 цифры в фактический байт в памяти в объекте bytes, возвращенном вызовом
codecs.decode, и структурировать для чтения 4 байта в буфере как одно 32-битное целое число.
Вы можете использовать
unhexlify()чтобы преобразовать шестнадцатеричную строку в двоичную форму, а затем использоватьstruct.unpack()чтобы декодировать значение little endian в int:>>> from struct import unpack >>> from binascii import unhexlify >>> n = unpack('<i', unhexlify('6c 02 00 00'.replace(' ','')))[0] >>> nВ строковый формат
'<i'мало что значит подписал обратным числом. Вы можете заменить'<I'или'<L'на unsigned int или long (оба 4 байта).Если данные не содержат пробелов, это упрощается до
>>> n = unpack('<i', unhexlify('6c020000'))[0]
Comments