/*!
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/