1. 程式人生 > >struct打包模組加強版!支援任意長度字串解包

struct打包模組加強版!支援任意長度字串解包

用過python的struct模組的人都知道,struct模組的打包並不方便,尤其是處理字串上。
字串的長度必須打包的時候計算好,比如‘hello’ 那麼打包格式 fmt就必須是‘5s’,因此fmt要麼固定一個最大字串長度 ‘180s’,要麼動態的去計算長度 ‘%ds’%len(text)
  1. 如果採用固定字串長度,那麼解包的時候你獲得的字串將會是這樣 ‘hello00x00x00x00x00x00x....’,因為python的字串不是像C\C++那樣以\0結尾來擷取的。
  2. 如果字串長度是在打包的時候才確定的,那麼解包的時候很被動,解包的時候怎麼知道fmt裡s到底有多少個?

於是乎我就寫了下面這個加強版struct模組,不過由於自己的程式設計水平有限,bug什麼的,這個模組可能並不能實際使用,拿出來分享一下也好,指點指點指不定就有思路改良出更好的實現。

import struct


"""
author:kaluluosi
date:2015-11-02


extension of struct lib
surport 
string argument auto encode
variable length string intelligent packing and unpacking,you don't need to set charactor count in fmt


"""


def pack(fmt,*values,encode='utf-8'):


    if fmt[0] in '@=<>!':
        mode = fmt[0]
        fmt = fmt[1:]
<span style="white-space:pre">	</span>
    #自動編碼
    if encode:
        new_values=[]
        for v in values:
            if isinstance(v,str):
                v=v.encode(encode)
            new_values.append(v)
        values = tuple(new_values)


    fmtbdr = [mode,]
    fmt =fmt.replace('x','') #將排版用的x佔位符去掉,x不佔位元組無意義
    
    for indx in range(len(fmt)):
        k = fmt[indx]
        if k in ('s', 'p'):
            text = values[indx]
            txtlen = len(text)+1 #計算出長度
            fmtbdr += '%ds'%txtlen
        else:
            fmtbdr+=k
    new_fmt = ''.join(fmtbdr)
    return struct.pack(new_fmt,*values)








def unpack(fmt,data,encode='utf-8'):


    print("unpack input:",len(data))
<span style="white-space:pre">	</span>
    if fmt[0] in '@=<>!':
        mode = fmt[0]
        fmt = fmt[1:]


    fmt =fmt.replace('x','') #將x排版用佔位符去掉
    new_data=bytes()
    fmtbdr =[mode,]
    cursor =0
    
    for k in fmt:
        if k in 'iIlLf':
            cursor+=4
            fmtbdr+=k
        elif k in 'cbB?':
            cursor+=1
            fmtbdr+=k
        elif k in 'hH':
            cursor+=4 if mode=='@'else 2
            fmtbdr+=k
        elif k in 'qQd':
            cursor+=8
            fmtbdr+=k
        elif k in 'P':
            cursor+=4
            fmtbdr+=k
        elif k in 'sp':
            length = 0
            b = data[cursor]
            while b!=0:
                length+=1
                cursor+=1
                b = data[cursor]
            fmtbdr+='%ds'%length
            new_data=data if mode=='@' else data[:cursor]+data[cursor+1:]
    new_fmt = ''.join(fmtbdr)


    values = struct.unpack(new_fmt,new_data)
    #decode 字串
    if encode:
        new_values=[]
        for v in values:
            if isinstance(v,bytes):
                v=v.decode(encode)
            new_values.append(v)
        values = tuple(new_values)
    return values




def main():
    data =pack('@hixcbsi',1,1,'a',1,'hello',0)
    print(len(data))
    values = unpack('@hixcbsi',data)
    print(values)


if __name__ == '__main__':
    main()
輸出結果
20
unpack input: 20
(1, 1, 'a', 1, 'hello', 0)
>>>