經(jīng)過簡化的需求如下:
請(qǐng)?jiān)O(shè)計(jì)并實(shí)現(xiàn)一個(gè)通用的詞表解析讀取工具類(一個(gè)或者幾個(gè)class/struct組成),
解析并讀取如下形式的詞表:
<col1>\t<col2>\t...\t<coln>
每一行都是一條記錄奕坟,每一列可能的類型包括
int
float
char *
uint32_t
uint64_t
其他用戶自定義類型
每一列的數(shù)據(jù)中均不包含\t字符祥款,每一行以\n結(jié)尾。
1對(duì)于非用戶自定義類型月杉,封裝解析行為刃跛;用戶自定義類型,調(diào)用用戶給出的parse函數(shù)(從string翻譯成用戶struct)完成
2 用戶能通過某些形式苛萎,定制這個(gè)詞表的結(jié)構(gòu)桨昙,指明每一列的類型是什么
3 用戶能逐行讀取這個(gè)詞表的信息,即按序讀取每一行腌歉,然后能解析出這一行中的每一列內(nèi)容
4 API設(shè)計(jì)友好蛙酪,做到自解釋
5 代碼的可讀性和可維護(hù)性好
程序一共由5個(gè)文件組成,3個(gè)頭文件翘盖,2個(gè)實(shí)現(xiàn)文件,如下:
1 build_in.h
#ifndef __BUILD_IN_H_
#define __BUILD_IN_H_
#include <stdint.h>
namespace parse
{
//int type
int parse(const char* str, int* result);
//char* type
int parse(const char* str, char* result);
int parse(const char* str, float* result);
int parse(const char* str, uint32_t* result);
int parse(const char* str, uint64_t* result);
}
2 build_in.cpp
#include <stdio.h>
#include <stdint.h>
#include "build_in.h"
namespace parse
{
//int type
int parse(const char* str, int* result)
{
int ret = 0;
if (NULL != str)
{
if (1 != sscanf(str, "%d", result))
{
ret = 1;
}
}
else
{
ret = 1;
}
return ret;
}
//char* type
int parse(const char* str, char* result)
{
int ret = 0;
if (NULL != str && NULL != result)
{
const char* start_str = str;
char* result_str = result;
while ('\t' != *start_str
&& '\n' != *start_str
&& '\0' != *start_str
&& ',' != *start_str)
{
*result_str++ = *start_str++;
}
*result_str = '\0';
}
else
{
ret = 1;
}
return ret;
}
}
3 parser.h
#ifndef __PARSER_H_
#define __PARSER_H_
#include "build_in.h"
#include "user.h"
#include <stdio.h>
#include <iostream>
namespace parse
{
class Parser
{
static const int MAX_COLUMN = 1024;
const char* column_[MAX_COLUMN];
int column_num_;
public:
Parser()
{
memset(this, '\0', sizeof(*this));
}
int parse_line(const char* line, const int column_num)
{
int ret = 0;
column_num_ = column_num;
do
{
if (NULL == line || column_num <= 0)
{
ret = 1;
break;
}
int index = 0;
for (int i = 0; '\n' != line[i]; i++)
{
if (0 == i)
{
column_[index++] = &line[i];
//printf("%s\n", column_[0]);
}
else if ('\t' == line[i])
{
column_[index++] = &line[i+1];
//printf("%s\n", column_[index-1]);
}
}
if (column_num != index)
{
ret = 1;
break;
}
} while(0);
return ret;
};
template<class T>
int get_column(const int index, T* result)
{
int ret = 0;
if (index < column_num_)
{
ret = parse(column_[index], result);
}
else
{
ret = 1;
}
return ret;
}
};
}
4 user.h
#ifndef __USER_H_
#define __USER_H_
#include <stdio.h>
namespace parse
{
//example
typedef struct MyStruct
{
int a;
int b;
int c;
}MyStruct;
int parse(const char* str, MyStruct* result);
}
5 user.cpp
#include "user.h"
namespace parse
{
//對(duì)于用戶類型桂塞,請(qǐng)自定義解析實(shí)現(xiàn)
int parse(const char* str, MyStruct* result)
{
sscanf(str, "%d %d %d", &result->a, &result->b, &result->c);
return 0;
}
}
核心的代碼在parser.h中,主要通過模板和函數(shù)重載來完成一種編譯期的多態(tài)行為馍驯。
調(diào)用實(shí)例如下:
#include "parser.h"
#include <stdio.h>
#include <iostream>
using namespace parse;
char* test1 = "abcdef\t123\t3.9\t456\tyiyg\n";
char* test2 = "abcdef\t3:4,5,6\t3.9\t456\tyiyg\t4:1,2,3,4\n";
char* test3 = "abcdef\t123\t3.9\t456\tyiyg\t22 33 44\n";
void test();
void test()
{
Parser test;
test.parse_line(test1, 5);
int x;
test.get_column(3, &x);
char* y = new char[20];
test.get_column(4, y);
float z;
test.get_column(2, &z);
printf("%d, %s, %f\n", x, y, z);
test.parse_line(test3, 6);
MyStruct my_struct;
test.get_column(5, &my_struct);
printf("%d %d %d\n", my_struct.a, my_struct.b, my_struct.c);
}
邏輯相對(duì)比較清晰阁危,就不過多解釋了。
(原文時(shí)間2014-2-20)