Преобразование шестнадцатеричной строки в целое число с помощью python



Обратите внимание, что задача состоит не из шестнадцатеричного к десятичному, а из строки шестнадцатеричных значений к целому числу.



Скажем, у меня есть жало от шестигранника (например. '6c 02 00 00'), поэтому мне нужно сначала преобразовать его в фактический шестнадцатеричный код, а затем получить целое число, которое он представляет... (этот конкретный будет 620 как int16 и int32)



Я перепробовал много вещей, но запутался еще больше. Есть ли быстрый способ сделать такое преобразование в python (желательно 3.х)?

652   2  

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". С этим значением мы просто вызываем класс Python int, который принимает вторичный необязательный параметр, обозначающий основание, которое должно использоваться для интерпретации числа, обозначенного в первом аргументе.

>>> int("".join("6c 02 00 00".split()[::-1]), 16)
620

Другой вариант-суммировать преобразование каждых 2 цифр, правильно сдвинутых к их весу в соответствии с их положением - это также может быть сделано в одном выражении с использованием reduce, хотя 4-строчный цикл Python for был бы больше читаем:

>>> 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)
620

Update ОП просто сказал, что у него на самом деле нет "пробелов" в строке - в этом случае можно использовать просто те же методы, но беря каждые две цифры вместо вызова 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

    Ничего не найдено.