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

之前提到了自定义的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路径

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值