/*!
python struct helper class
version : 0.01
created by : andrew.wu (erpingwu@gmail.com)
created on : 2009/05/23
url : http://blog.oolanguage.com/erpingwu/python-struct-module-helper-class/
*/
python struct 是一个很好用的 module ,能够很方便的处理 c struct, 但转换一个 c struct 到格式化字符串的工作有些繁琐.一个有效率的程序员应该是一个会偷懒的程序员,繁琐的工作应该尽量自动化.
c struct 可以写得很复杂,但大部分时候还是相对规范,那么先做一个简单的版本
以解释大智慧-Internet版的日线数据来做一个实例
struct DZHDay{ unsigned int trade_date; // 日期,转换为十进制即可 unsigned int open_price; // 开盘,除以1000 unsigned int high_price; // 最高,除以1000 unsigned int low_price; // 最低,除以1000 unsigned int close_price; // 收盘,除以1000 unsigned int turn_volume;// 成交额,除以10 unsigned int trading_volume ; // 成交量 unsigned int private_investor_line; // 散户线 unsigned int unknown1; // unsigned int unknown2; // };
首先,需要python能够自动取得struct的相关信息, 这里没有自己去实现什么,什么都自己做那就不是提高效率了,而是给自己找麻烦. 网上找到一个 CppHeaderParser.py 正好可以用来完成这个工作, 只需要稍做修改.
line 427: if (tok.value == 'class' or tok.value == 'struct'): line 452: elif (self.nameStack[0] == "class" or self.nameStack[0] == "struct"):
下面就贴代码了,看代码比什么都来得清楚
t.py
# -*- coding: utf-8-*- import os from struct import * from andrew.struct_helper import * import binascii dzh_day = ''' struct DZHDay{ unsigned int trade_date; // 日期,转换为十进制即可 unsigned int open_price; // 开盘,除以1000 unsigned int high_price; // 最高,除以1000 unsigned int low_price; // 最低,除以1000 unsigned int close_price; // 收盘,除以1000 unsigned int turn_volume;// 成交额,除以10 unsigned int trading_volume ; // 成交量 unsigned int private_investor_line; // 散户线 unsigned int unknown1; // unsigned int unknown2; // }; '''; import unittest class Tests(unittest.TestCase): def setUp(self): self.sh = StructHelper(); self.sh.parse(dzh_day, "DZHDay"); pass; def tearDown(self): pass def testOne(self): f = open(r"600050.day", 'rb'); data = f.read(); f.close() nt = self.sh.namedtuple._make(unpack(self.sh.format_string, data[0 : self.sh.unpack_size])); #print nt self.assertEqual(nt.trade_date, 20090521) def testTwo(self): #f = open(r"C:/dzh/DATA/SHase/Day/600388.day", 'rb'); f = open(r"600050.day", 'rb'); data = f.read(); f.close() #print binascii.b2a_hex(data) for index in range(0, len(data) / self.sh.unpack_size ): nt = self.sh.namedtuple._make( unpack_from( self.sh.format_string, data, self.sh.unpack_size*index) ); print "/n", nt pass; pass def main(): unittest.main() if __name__ == '__main__': main()
struct_helper.py
# struct helper class # version : 0.01 v # created by : andrew.wu (erpingwu@gmail.com) # created on : 2009/05/23 import os from struct import * from collections import namedtuple from CppHeaderParser import * class StructHelper(): _struct_format_table = { 'pad byte':'x', 'char':'c', 'signed char':'b', 'unsigned char':'B', 'bool':'?', 'BOOL':'?', 'short':'h', 'unsigned short':'H', 'int':'i', 'unsigned int':'I', 'long':'l', 'unsigned long':'L', 'long long':'q', 'unsigned long long':'Q', 'float':'f', 'double':'d', 'char[]':'s', 'void *':'P' } def type_to_fmt(self, type): return self._struct_format_table[type]; pass; def parse(self, code, struct_name): self.format_string = "" self.named_string = "" cpp_header = CppHeader(code , argType = "string") properties = cpp_header.classes[struct_name]["properties"]["private"] for p in properties: self.format_string += self.type_to_fmt(p["type"]) self.named_string += p["name"] + " " self.unpack_size = calcsize(self.format_string) self.namedtuple = namedtuple(struct_name, self.named_string) pass; pass;
output
.
DZHDay(trade_date=20090521, open_price=6400, high_price=6410, low_price=6180, cl ose_price=6240, turn_volume=2085205, trading_volume=3334743, private_investor_li ne=373549, unknown1=4857, unknown2=2136735744)
DZHDay(trade_date=20090522, open_price=6210, high_price=6290, low_price=6170, cl ose_price=6260, turn_volume=1023114, trading_volume=1639956, private_investor_li ne=385, unknown1=4873, unknown2=0) .
----------------------------------------------------------------------
Ran 2 tests in 0.000s OK
相关引用
CppHeaderParser-1.05 http://sourceforge.net/projects/cppheaderparser/
PLY (Python Lex-Yacc) 3.2 http://www.dabeaz.com/ply/
Python 2.6 http://www.python.org/