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

代码自动生成工具(一)-Csv读表代码自动生成工具

2017-01-05 13:54 543 查看
之前提到了自定义的Csv格式的表格读取的一个工具类CsvReader

这里我们实现一个可以对任意符合我们人为规定的格式的Csv文件,自动生成其对应的读表代码

本工具需要boost库支持,本人用的是1.55.0

这里首先定义Csv中支持的几种列类型:FieldType:包括有/无符号整数,小数,字符串,子结构

enum FieldType
{
FT_int = 0,		//整数
FT_uint,		//整数
FT_float,		//浮点数
FT_string,		//字符串
FT_struct,		//子结构
FT_unknow,
};


列类型为子结构时,对于子结构信息的定义:ChildStruct:包括字段名,字段类型

class ChildStruct
{
public:
ChildStruct();
ChildStruct(const ChildStruct &other);
ChildStruct& operator = (const ChildStruct &other);
~ChildStruct();

std::vector<std::string> m_arrChildName;	// 子结构的字段名称
std::vector<FieldType> m_arrFieldType;		// 子结构的字段类型
};


整个表格文件,前3行涉及的信息的定义:TableFile:包括表名称,列名称,列类型,注释,是否是主键,是否是数组

class CsvFile
{
public:
CsvFile();
CsvFile(const CsvFile &other);
CsvFile& operator = (const CsvFile &other);
~CsvFile();

std::string m_strClassName;					// 类名称

std::vector<std::string> m_arrName;			// 列名称(原始名称)
std::vector<std::string> m_arrType;			// 列类型标识字符串
std::vector<std::string> m_arrComments;		// 列注释

std::vector<int> m_arrKey;					// 主键列下标

std::vector<bool> m_arrIsList;				// 列是否是不定长数组(lst)
std::vector<FieldType> m_arrFieldType;		// 列类型枚举

std::map<int, ChildStruct> m_mapChildStruct;// 嵌套的子结构字段名称,类型映射表
};


Csv文件解析类,读取文件文本内容,按相应配置(命名空间,文件路径等),解析生成相应的CsvFile对象,

class CsvParse
{
public:
CsvParse();
~CsvParse();

bool ParseFile(const std::string& fullPathName);

// 解析完毕的csv文件信息列表
std::map<std::string, CsvFile> m_Files;

// csv文件解析工具输入参数
public:
std::string m_NameSpace; // 自定义命名空间
bool m_ThreadSpecific;	// 是否需要线程本地表格数据
std::vector<std::string> m_CsvFileName; // 待处理的csv文件列表
std::string m_LoaderPath; // loader输出cpp代码路径
std::string m_HelperPath; // helper输出cpp代码路径
};

传入一个Csv的文件完整路径,调用CsvReader,读取出列名称,列类型,列注释

对于列名称,调用StringTool进行首字母大写

对于列类型,按照自定义Csv格式解析出对应类型或子结构

对于列注释,如果是Utf8,则调用StringTool转换成GBK

具体的代码生成包含两部分功能:

void ParseCsv2LoaderH(const CsvParse& csvParse)

void ParseCsv2LoaderCpp(const CsvParse& csvParse)

void ParseCsv2HelperH(const CsvParse& csvParse)

void ParseCsv2HelperCpp(const CsvParse& csvParse)

传入一个解析好的CsvParse对象,生成具体代码

Loader生成对应的读取代码,读取csv文件的每一行数据,转成相应的数据结构。

Helper生成一个空的辅助类,用于需要对数据重新组织的情况,比如配置中是按某个id列作为主键,存成一个map,提供查找,但是实际逻辑中还需要按某个名称列作为索引,再提供一个map,用于提供按名称查找(或者模糊查找),这时候就需要手动再提供一个新的查找函数,就可以写在helper中

需要生成的代码包括:

// 1、头文件:map,vector等
//
// 2、命名空间(由程序运行参数决定)
//
// 3、每个子结构:class XXX {...};
// 包括:
// 构造:XXX() {...}
// 拷贝构造:XXX(const XXX &other) {...}
// 赋值:XXX& operator = (const XXX &other) {...}
// 赋值:XXX& operator = (const std::string &other) {...}
// 子结构的各个字段罗列
//
// 4、表结构:class XXX {...};
// 包括:
// 构造:XXX() {...}
// 拷贝构造:XXX(const XXX &other) {...}
// 赋值:XXX& operator = (const XXX &other) {...}
// 表结构的各个字段罗列
//
// 5、表结构对应的管理器类:class XXXTable {...};
// 包括:
// 构造:XXXTable();
// 析构:~XXXTable();
// 获取表格数据:Get
//     对于3个主键的,则生成:
//     const XXX* Get(k1, k2, k3){...}
//     const std::map<k3type, XXX>* Get(k1, k2){...}
//     const std::map<k2type, std::map<k3type, XXX> >* Get(k1){...}
//     const std::map<k1type, std::map<k2type, std::map<k3type, XXX> > >& Get(){...}
//     对于2个主键的则生成:
//     const XXX* Get(k1, k2);
//     const std::map<k2type, XXX>* Get(k1);
//     const std::map<k1type, std::map<k2type, XXX> >& Get();
//     对于1个主键的则生成:
//     const XXX* Get(k1);
//     const std::map<k1type, XXX>& Get();
//     对于没有主键的,那么按照数组处理,生成:
//     const XXX* Get(index);
//     const std::vector<XXX>& Get();
// 表格加载:bool Load(const wchar_t* pFilePathName);
// 表格管理器的成员:
// 表格数据列表:m_XXXs,有主键的则为map,没有主键的则为vector


main函数涉及两个小功能:

一个是遍历输入参数,解析名命名空间,待处理的csv文件,代码生成路径

一个是迭代每一个待处理的csv文件名,传入CsvParse解析,然后对解析完的结果,逐个生成相应代码

完整的代码,比较长,这里就不贴了

给一个生成后的代码的示例吧:

还是前文的例子:



如上表格,namespace=common.table.csv

生成的头文件如下所示,

#ifndef __TestCsvLoader_h__
#define __TestCsvLoader_h__

#include <string>
#include <vector>
#include <map>

namespace common{
namespace table{
namespace csv{

class Test
{
public:
class Struct
{
public:
Struct();
Struct(const Struct &other);
Struct& operator = (const Struct &other);
Struct& operator = (const std::string &other);

unsigned int m_StructId;
int m_StructNum;
float m_StructFloat;
std::string m_StruceName;
};

class StructList
{
public:
StructList();
StructList(const StructList &other);
StructList& operator = (const StructList &other);
StructList& operator = (const std::string &other);

unsigned int m_StructId;
int m_StructNum;
float m_StructFloat;
std::string m_StruceName;
};

Test();
Test(const Test &other);
Test& operator = (const Test &other);

unsigned int m_Id1;	//测试主键1
int m_Id2;	//测试主键2
unsigned int m_Id3;	//测试主键3
std::string m_Str;	//测试字符串
std::vector<unsigned int> m_UInts;	//测试数字列表
float m_Float;	//测试数字
Struct m_Struct;	//测试子结构
std::vector<StructList> m_StructLists;	//测试子结构列表
};

class TestCsvLoader
{
public:
TestCsvLoader()
{
}
~TestCsvLoader()
{
}

const Test* Get(unsigned int id1, int id2, unsigned int id3) const;
const std::map<unsigned int, Test>* Get(unsigned int id1, int id2) const;
const std::map<int, std::map<unsigned int, Test> >* Get(unsigned int id1) const;
const std::map<unsigned int, std::map<int, std::map<unsigned int, Test> > >& Get() const;

bool LoadFile(const char* szPath);
bool ReloadFile(const char* szPath);

private:
std::map<unsigned int, std::map<int, std::map<unsigned int, Test> > > m_Tests;
};

}
}
}
#endif


放上完整工程的下载链接

工程中的boost库的路径为作者本机的路径,VS编译时请选择Release,重新配置boost库的include路径和lib路径
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  csv 代码自动生成