一、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消息體結構