Python bitstring模块介绍
一、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。
四、使用方法
1
2
3
4
|
from bitstring import BitArray, BitStream a = BitArray( '0xff01' ) b = BitArray( '0b110' ) |
注意此处应传入字符串,若直接传入整型参数,则表示创建一个bit位数为该整型参数值的对象。
1
2
3
|
>>> s = BitArray( 3 ) >>> s BitArray( '0b000' ) |
1
2
3
4
|
>>> type (a) < class 'bitstring.BitArray' > >>> type (b) < class 'bitstring.BitArray' > |
上述代码实例化了两个对象,a和b便可以调用BitArray的方法。
其他构造方法
1
2
3
4
5
6
7
8
9
10
|
# 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' ) |
进制转换
1
2
3
4
5
6
7
8
|
>>> a. bin '1111111100000001' >>> b. oct '6' >>> b. int - 2 >>> a.bytes b '\xff\x01' |
注意,转换后的进制类型为字符串。
bit位增加与减少
此处的操作类似于字符串的叠加,注意+前后的变量顺序会影响结果。
1
2
3
4
|
>>> (b + [ 0 ]). hex 'c' >>> ([ 0 ] + b). hex '6' |
1
2
3
4
5
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的字符串进行叠加。
以列表/字符串的方法按字符串进行操作
1
2
3
4
5
|
>>> print (a[ 3 : 9 ]) 0b111110 >>> del a[ - 6 :] >>> print (a) 0b1111111100 |
1
2
3
|
>>> a.prepend( '0b01' ) >>> a.append( '0o7' ) >>> a + = '0x06' |
以字符串的方式进行查找和替换
1
2
3
|
>>> a = BitArray( '0xa9f' ) >>> a.find( '0x4f' ) ( 3 ,) |
find方法返回所有符合条件的起始下标,此处的下标指的是bit的下标。
a按字符串进行拆分可以分成三个字符串的叠加。
1
2
|
>>> a = = '0b101, 0x4f, 0b1' True |
1
2
3
4
5
|
>>> a = BitArray( '0b110111100000110' ) >>> a.replace( '0b110' , '0b1' ) 3 >>> a. bin '111100001' |
replace方法则是将符合条件的进行替换。
构造bitstring
使用pack方法进行构建,传入格式和变量值,则会一一对应进行构造,注意此方法返回的是bitstream类型。
1
2
|
width, height = 352 , 288 s = bitstring.pack( '0x000001b3, 2*uint:12' , width, height) |
其中‘2*uint:12’表示构造两个bit位为12的变量,对应的是width和height变量,‘0x000001b3’本身就是格式化后的变量值,因此不需要再传入变量。
除了上述方法,还可以将格式和变量值作为变量传入。
1
2
3
4
5
6
7
8
9
10
11
12
|
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'),若构造的参数无法转换成十六进制,则会返回两个字符串。
1
2
3
4
5
6
7
8
9
10
11
12
|
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')
除此之外还有另外一种构造方法。
1
2
3
4
5
6
7
8
|
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开始。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
>>> 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还能以列表的方式一次性返回多个解析值。
1
2
|
>>> s.readlist( '2*uint:12' ) [ 352 , 288 ] |
通过格式化的形式解析。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
# 十六进制数据消息 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,可以按照一定的格式从头开始解析。
1
2
|
>>> 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则是每次都是从头开始解析。
大端模式与小端模式
1
2
3
4
5
6
7
|
>>> 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消息体结构