一、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消息体结构