2012-03-30 5 views
10

Я читаю двоичный файл в Python и документацию для формата файла говорит:Python: Извлечение битов из байта

Flag (в двоичной системе) Значение

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?

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

+0

, связанный: [Использование Python. Как я могу прочитать биты в байте?] (Http://stackoverflow.com/q/2576712/4279) – jfs

ответ

7

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

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

Я нахожу двоичные числа легче понять, чем гекс при выполнении битового маскирования.

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 
+0

Спасибо. Я тоже предпочитаю двоичные числа в этом случае. –

+0

@EvanBorgstrom На Python 3 вы можете написать: data = b '\ xaa \ x55 \ x00 \ x80'' и 'для байта в данных: ...'. Не используйте имя 'bytes', это встроенный тип. – jfs

9

Классический подход проверки, установлен ли бит, чтобы использовать двоичный «и» оператор, т.е.

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

Чтобы проверить, установлен ли п^й бит, использовать силу двух, т.е.

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

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

Спасибо, но это не отвечает на мой вопрос. Учитывая byte = 178, как бы вы извлекли флаг == 1 & numbytes == 50? –

+1

+1: но вам не нужна часть! = 0, 'if x & 0b10' должно быть достаточно. – tom10

+1

'! = 0' не так плохо, как' == True', но он близок. :) –

0

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

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

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

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

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

def GetVal(b): 
    # mask off the most significant bit, see if it's 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) 
0

там вы идете:

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 
0

Вместо междунар (bin (байт) [3:], 2), вы можете просто использовать: int (bin (байт >> 1), 2)