您的位置:首页 > 编程语言 > Python开发

struct打包模块加强版!支持任意长度字符串解包

2015-11-14 02:24 681 查看
用过python的struct模块的人都知道,struct模块的打包并不方便,尤其是处理字符串上。

字符串的长度必须打包的时候计算好,比如‘hello’ 那么打包格式 fmt就必须是‘5s’,因此fmt要么固定一个最大字符串长度 ‘180s’,要么动态的去计算长度 ‘%ds’%len(text)

如果采用固定字符串长度,那么解包的时候你获得的字符串将会是这样 ‘hello00x00x00x00x00x00x....’,因为python的字符串不是像C\C++那样以\0结尾来截取的。
如果字符串长度是在打包的时候才确定的,那么解包的时候很被动,解包的时候怎么知道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)
>>> 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  struct python