Python: извлечение битов из байта

Я читаю двоичный файл в python, и в документации для формата файла говорится:

Флаг (в двоичном выражении) Значение

1 nnn nnnn Указывает, что имеется один байт данных                 который должен быть дублирован nnn nnnn (максимум 127)                 раз.

0 nnn nnnn Указывает, что есть nnn nnnn байты изображения                 данные для наблюдения (максимум 127 байт) и                 нет дубликатов.

n 000 0000 Поле конца строки. Обозначает конец строки                 запись. Значение n может быть либо нулевым, либо одним.                 Обратите внимание, что поле конца строки требуется и                 что он отражается в длине записи строки                 поле, упомянутое выше.

При чтении файла я ожидаю, что байт я должен вернуть 1 nnn nnnn, где часть nnn nnnn должна быть 50.

Я смог сделать это, используя следующее:

flag = byte >> 7
numbytes = int(bin(byte)[3:], 2)

Но вычисление numbytes похоже на дешевое обходное решение.

Могу ли я сделать больше бит математики, чтобы выполнить вычисление numbytes?

Как вы подходите к этому?

Ответ 1

Вы можете отключить ведущий бит, используя маску ANDed с байтом из файла. Это оставит вас со значением остальных бит:

mask =  0b01111111
byte_from_file = 0b10101010
value = mask & byte_from_file
print bin(value)
>> 0b101010
print value
>> 42

Я считаю, что двоичные числа легче понять, чем hex при выполнении маскировки.

EDIT: чуть более полный пример для вашего варианта использования:

LEADING_BIT_MASK =  0b10000000
VALUE_MASK = 0b01111111

bytes = [0b10101010, 0b01010101, 0b0000000, 0b10000000]

for byte in bytes:
    value = byte & VALUE_MASK
    has_leading_bit = byte & LEADING_BIT_MASK
    if value == 0:
        print "EOL"
    elif has_leading_bit:
        print "leading one", value
    elif not has_leading_bit:
        print "leading zero", value

Ответ 2

Классический подход проверки того, установлен ли бит, заключается в использовании двоичного "и" оператора, т.е.

x = 10 # 1010 in binary
if x & 0b10 != 0:
    print('Second bit is set')

Чтобы проверить, установлен ли n ^ -й бит, используйте значение 2, т.е.

def is_set(x, n):
    return x & 2**n != 0 

is_set(10, 1) # 1 because we count from 0th bit
>>> True

Ответ 3

Если я правильно прочитал ваше описание:

if (byte & 0x80) != 0:
    num_bytes = byte & 0x7F

Ответ 5

Не уверен, что я правильно вас понял, но если бы я это сделал, это должно было сделать трюк:

>>> x = 154 #just an example
>>> flag = x >> 1
>>> flag
1
>>> nb = x & 127
>>> nb
26

Ответ 6

Вы можете сделать это следующим образом:

def GetVal(b):
   # mask off the most significant bit, see if it set
   flag = b & 0x80 == 0x80
   # then look at the lower 7 bits in the byte.
   count = b & 0x7f
   # return a tuple indicating the state of the high bit, and the 
   # remaining integer value without the high bit.
   return (flag, count)

>>> testVal = 50 + 0x80
>>> GetVal(testVal)
(True, 50)

Ответ 7

там вы идете:

class ControlWord(object):
    """Helper class to deal with control words.

    Bit setting and checking methods are implemented.
    """
    def __init__(self, value = 0):
        self.value = int(value)
    def set_bit(self, bit):
        self.value |= bit
    def check_bit(self, bit):
        return self.value & bit != 0
    def clear_bit(self, bit):    
        self.value &= ~bit

Ответ 8

Вместо int (bin (byte) [3:], 2) вы можете просто использовать: int (bin (byte → 1), 2)