web-dev-qa-db-ja.com

Python:バイトからビットを抽出する

私はpythonでバイナリファイルを読んでおり、ファイル形式のドキュメントはこう言っています:

フラグ(バイナリ)意味

1 nnn nnnn続くnnn nnnn(最大127回)のデータバイトが続くことを示します。

0 nnn nnnn nnn nnnnバイトの画像データ(最大127バイト)があり、重複がないことを示します。

n 000 0000行末フィールド。行レコードの終わりを示します。 nの値は0または1のいずれかです。行末フィールドは必須であり、上記の行レコードフィールドの長さに反映されることに注意してください。

ファイルを読み取るとき、私は1 nnn nnnnを返すバイトを期待しています。ここで、nnn nnnnの部分は50でなければなりません。

私はこれを以下を使用して行うことができました:

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

しかし、numbytesの計算は安価な回避策のように感じられます。

Numbytesの計算を実行するために、より多くのビット計算を実行できますか?

これにどのように取り組みますか?

21
Evan Borgstrom

ファイルのバイトとAND演算されたマスクを使用して、先頭ビットを取り除くことができます。残りのビットの値が残ります。

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

ビットマスキングを行う場合、2進数は16進数よりも理解しやすいと思います。

編集:あなたのユースケースのもう少し完全な例:

LEADING_BIT_MASK =  0b10000000
VALUE_MASK = 0b01111111

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

for v in values:
    value = v & VALUE_MASK
    has_leading_bit = v & 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
12
alan

ビットが設定されているかどうかを確認する古典的なアプローチは、バイナリの「and」演算子を使用することです。

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

N ^番目のビットが設定されているかどうかを確認するには、2の累乗、またはより良いビットシフトを使用します。

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

    # a more bitwise- and performance-friendly version:
    return x & 1 << n != 0

is_set(10, 1) # 1 i.e. first bit - as the count starts at 0-th bit
>>> True
16
Zaur Nasibov

説明を正しく読んだ場合:

if (byte & 0x80) != 0:
    num_bytes = byte & 0x7F
1
D.Shawley

あなたはこのようにそれを行うことができます:

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
bgporter

そこに行きます:

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
K.-Michael Aye

Int(bin(byte)[3:]、2)の代わりに、単に次のように使用できます:int(bin(byte >> 1)、2)

0
theonova

私があなたを正しく手に入れたかどうかはわかりませんが、私がそうした場合、これでうまくいくはずです:

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