一、bitstring簡介
A Python module to help you manage your bits。
這是一個便於管理bit的Python模塊,其方便性在於借鑒Python中字符串和列表的特性來管理bit。
二、安裝方法
直接 pip install bitstring。
三、常用類
bitstring模塊有四個類,Bits、ConstBitStream、BitArray、BitStream,其中BitArray繼承自Bits,而BitStream繼承自ConstBitStream和BitArray,而ConstBitStream也是繼承自Bits。
四、使用方法
from bitstring import BitArray, BitStream a = BitArray('0xff01') b = BitArray('0b110')
注意此處應傳入字符串,若直接傳入整型參數,則表示創建一個bit位數為該整型參數值的對象。
>>> s=BitArray(3) >>> s BitArray('0b000')
>>> type(a) <class 'bitstring.BitArray'> >>> type(b) <class 'bitstring.BitArray'>
上述代碼實例化了兩個對象,a和b便可以調用BitArray的方法。
其他構造方法
# from a binary string a = BitArray('0b001') # from a hexadecimal string b = BitArray('0xff470001') # straight from a file c = BitArray(filename='somefile.ext') # from an integer d = BitArray(int=540, length=11) # using a format string d = BitArray('int:11=540')
進制轉換
>>> a.bin '1111111100000001' >>> b.oct '6' >>> b.int -2 >>> a.bytes b'\xff\x01'
注意,轉換后的進制類型為字符串。
bit位增加與減少
此處的操作類似於字符串的疊加,注意+前后的變量順序會影響結果。
>>> (b + [0]).hex 'c' >>> ([0] + b).hex '6'
>>> b+[0]*3 BitArray('0b110000') >>> b+[1]*2 BitArray('0b11011') >>> b+5 BitArray('0xc0')
此處可用BitArray([0])、BitArray('0b0')、BitArray(bin='0')、'0b0'等方式代替[0],或者直接用整型,比如5,此時代表操作5個bit為0的字符串進行疊加。
以列表/字符串的方法按字符串進行操作
>>> print(a[3:9]) 0b111110 >>> del a[-6:] >>> print(a) 0b1111111100
>>> a.prepend('0b01') >>> a.append('0o7') >>> a += '0x06'
以字符串的方式進行查找和替換
>>> a = BitArray('0xa9f') >>> a.find('0x4f') (3,)
find方法返回所有符合條件的起始下標,此處的下標指的是bit的下標。
a按字符串進行拆分可以分成三個字符串的疊加。
>>> a == '0b101, 0x4f, 0b1' True
>>> a=BitArray('0b110111100000110') >>> a.replace('0b110','0b1') 3 >>> a.bin '111100001'
replace方法則是將符合條件的進行替換。
構造bitstring
使用pack方法進行構建,傳入格式和變量值,則會一一對應進行構造,注意此方法返回的是bitstream類型。
width, height = 352, 288 s = bitstring.pack('0x000001b3, 2*uint:12', width, height)
其中‘2*uint:12’表示構造兩個bit位為12的變量,對應的是width和height變量,‘0x000001b3’本身就是格式化后的變量值,因此不需要再傳入變量。
除了上述方法,還可以將格式和變量值作為變量傳入。
fmt = 'sequence_header_code, uint:12=horizontal_size_value, uint:12=vertical_size_value, uint:4=aspect_ratio_information' d = {'sequence_header_code': '0x000001b3', 'horizontal_size_value': 352, 'vertical_size_value': 288, 'aspect_ratio_information': 1 } s = bitstring.pack(fmt, **d)
以上代碼s的結果為BitStream('0x000001b31601201'),若構造的參數無法轉換成十六進制,則會返回兩個字符串。
fmt = 'sequence_header_code, uint:11=horizontal_size_value, uint:12=vertical_size_value, uint:4=aspect_ratio_information' d = {'sequence_header_code': '0x000001b3', 'horizontal_size_value': 352, 'vertical_size_value': 288, 'aspect_ratio_information': 1 } s = bitstring.pack(fmt, **d)
以上代碼s的結果為BitStream('0x000001b32c0240, 0b001')
除此之外還有另外一種構造方法。
format = 'hex:32=start_code, uint:12=width, uint:12=height' # 方法一 d = {'start_code': '0x000001b3', 'width': 352, 'height': 288} s = bitstring.pack(format, **d) # 方法二 s = bitstring.pack(format, width=352, height=288, start_code='0x000001b3')
解析BitStream
BitStream繼承自BitArray,擁有BitArray的所有方法,同時又繼承自ConstBitStream,因此多了解析方法。
BitStream可根據下標pos來進行索引和讀取,默認從0開始。
>>> s BitStream('0x000001b31601201') >>> s.pos 0 >>> s.read(24) BitStream('0x000001') >>> s.pos 24 >>> s.read('hex:8') 'b3' >>> s.pos 32
read函數中直接填整型數字,則表示從pos位置開始切換該整型值,返回一個新的BitStream。
read函數還可以指定返回的類型,如s.read("hex:8"),表示從pos位置開始讀取8個bit,並以十六進制的方式進行返回,返回的是字符串。
s.read("int:8"),表示從pos位置開始讀取8個bit,並以十進制的方式進行返回,返回的是整型。
BitStream還能以列表的方式一次性返回多個解析值。
>>> s.readlist('2*uint:12') [352, 288]
通過格式化的形式解析。
# 十六進制數據消息 recv_data = "0200000002040000000C00000013093132372E302E302E31" # 解析消息 bs = bitstring.BitStream(hex=recv_data) fmt_head2 = """ hex:32=id_hex, hex:8=valueLen_hex, """ res_list = bs.readlist(fmt_head2) id_hex = res_list[0] valueLen_hex = res_list[1] valueLen = int(valueLen_hex, base=16) fmt_head3 = """ hex:valueLen_hex=value_hex, """ res_list = bs.readlist(fmt_head3, valueLen_hex=valueLen * 8) value_hex = res_list[0]
另外,BitStream提供了一種和readlist類似的方法unpack,可以按照一定的格式從頭開始解析。
>>> s.unpack('bytes:4, 2*uint:12, uint:4') ['\x00\x00\x01\xb3', 352, 288, 1]
若中間有x個bit位不需要解析時,可在fmt中使用pad:x來占位,則返回的解析列表不會包含pad占位的內容。
readlist和unpack的區別在於readlist是根據s.pos值來確定解析的起始位置,而unpack則是每次都是從頭開始解析。
大端模式與小端模式
>>> big_endian = BitArray(uintbe=1, length=16) >>> big_endian BitArray('0x0001') >>> little_endian = BitArray(uintle=1, length=16) >>> little_endian BitArray('0x0100')
利用bitstring模塊解析JT808報文
JT808消息結構
JT808消息頭結構
JT808消息體結構