Как установить биты внутри байта объекта, который представляет шестнадцатеричные символы в Python - PullRequest
0 голосов
/ 27 сентября 2018

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

print(type(a)) # --> <class 'bytes'>

Начиная с a = b'2900BC' Я хочу получить что-то вроде a = b'29F0BC', вызвав некоторую функциюаналогично

replace_hex_symbol(input, index, value)

в моем случае

replace_hex_symbol(a,2,F)

Значение для установки символа номер 2 в объекте a на значение F (как f_hex = 1111_bin)

КакНасколько я понимаю, одна проблема заключается в том, что объект типа байтов не является изменяемым.Даже с превращением его в bytearray я не могу сделать это.В Python уже есть хороший способ для выполнения таких манипуляций или есть кто-то умный трюк, как заменить части в этом объекте, полном шестнадцатеричных символов?

1 Ответ

0 голосов
/ 27 сентября 2018

bytes объекты обычно имеют те же методы, что и строки;оба являются неизменяемыми, но это не мешает вам создавать новые объекты на основе старого значения.

Например, вы можете создать новое значение bytes со всеми символами 2 ASCII, замененными на F Символ ASCII с методом bytes.replace() :

>>> b'2900BC'.replace(b'2', b'F')
b'F900BC'

См. Операции с байтами и байтами раздел документации по стандартным типам Pythonдля списка методов, которые поддерживаются.Обратите внимание, что аргументы bytes.replace() должны сами по bytes значениям!

С точки зрения вашей replace_hex_symbol() функции:

def replace_hex_symbol(a, old, new):
    # ensure that both old and new are actually bytes
    if not isinstance(old, bytes):
        old = old.encode('ascii')
    if not isinstance(new, bytes):
        new = new.encode('ascii')
    return a.replace(old, new)

Далее, bytearray объекты в основном являются изменяемымиподкласс bytes;у них те же методы, но вы также можете напрямую обращаться к индексам и обновлять их.См. Типы изменяемых последовательностей Документация .

Оба объекта bytes и bytearray являются последовательностями целых чисел в диапазоне 0-255 и индексирование отражает это.При присваивании одному индексу bytearray вы должны использовать целые числа:

>>> b = bytearray(b'2900BC')
>>> b
bytearray(b'2900BC')
>>> b[0]
50
>>> b[0] = ord('F')  # ascii codepoint for F
>>> b
bytearray(b'F900BC')

, но вы также можете индексировать с помощью срезов (в том числе в присваиваниях), после чего вы получаете тот же объект последовательности снова при получениии любая последовательность байтов является приемлемой (включая объект bytes или список целых чисел).

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

На самом деле, в шестнадцатеричных последовательностях символов нет ничего, что указывало бы, что они должны быть bytes значениями!Вы также можете использовать объект str или список отдельных шестнадцатеричных символов, если вы должны иметь изменяемый тип:

>>> '2900BC'  # string
'2900BC'
>>> list('2900BC')  # list of characters
['2', '9', '0', '0', 'B', 'C']

Если вы вместо этого имели дело с двоичными данными закодированы в виде шестнадцатеричных цифр, затем преобразуйте эти закодированные данные в значение bytes с помощью bytes.fromhex() фабричного метода и вернитесь к bytes.hex();bytearray объекты поддерживают одинаковые преобразования.

В этот момент шестнадцатеричные цифры преобразуются в 4-битные полубайты каждый, и вам нужна четная длина шестнадцатеричных цифр:

>>> bytes.fromhex('2900BC')
b')\x00\xbc'
>>> list(bytes.fromhex('2900BC'))  # show individual byte integer values
[41, 0, 188]

и выпришлось бы использовать битовое смещение и маскировку , чтобы установить отдельные клевы.Например, 2 во входном шестнадцатеричном коде является наиболее значимым полубайтом в первом байте, поэтому F hex или 15 десятичное число должно быть смещено на 4 бита, а затем объединено с младшим 4биты этого первого байта:

>>> a = bytearray.fromhex('2900BC')  # mutable sequence of 3 bytes
>>> a[0] = (0xF << 4) | (a[0] & 0xF)  # set upper nibble, preserve lower
>>> a
bytearray(b'\xf9\x00\xbc')
>>> a.hex()
'f900bc'

См. управление битами страница в вики Python.Однако, если вам нужен этот уровень манипуляции в более широком масштабе, рассмотрите стороннюю библиотеку, такую ​​как bitstring, чтобы упростить вам эту задачу.

...