做数据处理时经常会用读这样的文本文件:
1,10,1,11,1,13,1,12,1,1,9
2,11,2,13,2,10,2,12,2,1,9
3,12,3,11,3,13,3,10,3,1,9
4,10,4,11,4,1,4,13,4,12,9
4,1,4,13,4,12,4,11,4,10,9
1,2,1,4,1,5,1,3,1,6,8
1,9,1,12,1,10,1,11,1,13,8
2,1,2,2,2,3,2,4,2,5,8
3,5,3,6,3,9,3,7,3,8,8
4,1,4,4,4,2,4,3,4,5,8
有时候每一行的数据个数也不是确定的,但我们想按行保存在数组或vector(list)中,这么久以来用习惯了java的readLine()和split(","),突然用c++,感觉到寸步难行,于是自己写了一个函数,用c++读取数值文件。
/* *读取绝对路径为filePath的文件,文件中每行中的数值以tag字符分开 *返回vector<vector<string>>格式的数据 */ vector<vector<string>> readFile(char tag,string filePath){ ifstream fileReader; fileReader.open(filePath,ios::in);//以只读方式打开 vector<vector<string>> data;//以2维向量的形势保持整个文件 while(!fileReader.eof()){//未到文件末尾 string linestring; getline(fileReader,linestring);//读取一行 vector<string> line = split(linestring,tag);//分割每行,并放在line向量中 data.push_back(line); } return data; }
readFile()函数读取文件,其中调用了一个split()函数,用于将一个string类型的字符串分割为字符串向量,实现如下:
/* *对字符串inputString按tag字符分割 *返回vector<string>格式的一维向量 */ vector<string> split(string inputString,char tag){ int length = inputString.length(); int start=0;//数值起始下标 vector<string> line; for(int i=0;i<length;i++){ if(inputString[i] == tag){//遇到tag字符 string sub = inputString.substr(start,i-start); //取inputString[start]-inputString[i]子串 line.push_back(sub);//压入向量中 start = i+1; }else if(i==length-1){ string sub = inputString.substr(start,i-start+1);//最后一个字符没有标点,需单独处理 line.push_back(sub);//压入向量中 } } return line; }
调用readFile()函数就可以将文件以vector<vector<string>>类型读入内存。但既然是数值,我们肯定要进行计算,字符串数组对我们还是没有,需要转化为数值类型vector<vector<int或double或float>>,这里写了一个转行函数:
/* *将inputString转化成数值型,利用模板,实现复用 */ template <typename T> void transToNum(string inputString,T *result){ const char *p = inputString.c_str(); char * type = getType(*result); if(type== "int") *result = atoi(p); else if(type== "double") *result = atof(p); else if(type== "float") *result = atof(p); }
这里利用模板实现了复用,为了能在运行时知道变量的值,c++里面没有getClass(),所有只有自己写了,这里写了一个getType()函数:
char * getType(int x){//返回整数类型 return "int"; } char * getType(double x){//返回double类型 return "double"; } char * getType(float x){//返回float类型 return "float"; }
这样最终能得到vector<vector<int或double或float>>类型的数据,进行你想要的处理。
以下测试部分和完整代码:
#include <iostream> #include <vector> #include <fstream> #include <string> #include <ctime> using namespace std; vector<vector<string>> readFile(char tag,string filePath); vector<string> split(string inputString,char tag); template <typename T> void transToNum(string inputString,T *result); /* *读取绝对路径为filePath的文件,文件中每行中的数值以tag字符分开 *返回vector<vector<string>>格式的数据 */ vector<vector<string>> readFile(char tag,string filePath){ ifstream fileReader; fileReader.open(filePath,ios::in);//以只读方式打开 vector<vector<string>> data;//以2维向量的形势保持整个文件 while(!fileReader.eof()){//未到文件末尾 string linestring; getline(fileReader,linestring);//读取一行 vector<string> line = split(linestring,tag);//分割每行,并放在line向量中 data.push_back(line); } return data; } /* *对字符串inputString按tag字符分割 *返回vector<string>格式的一维向量 */ vector<string> split(string inputString,char tag){ int length = inputString.length(); int start=0;//数值起始下标 vector<string> line; for(int i=0;i<length;i++){ if(inputString[i] == tag){//遇到tag字符 string sub = inputString.substr(start,i-start); //取inputString[start]-inputString[i]子串 line.push_back(sub);//压入向量中 start = i+1; }else if(i==length-1){ string sub = inputString.substr(start,i-start+1);//最后一个字符没有标点,需单独处理 line.push_back(sub);//压入向量中 } } return line; } char * getType(int x){//返回整数类型 return "int"; } char * getType(double x){//返回double类型 return "double"; } char * getType(float x){//返回float类型 return "float"; } /* *将inputString转化成数值型,利用模板,实现复用 */ template <typename T> void transToNum(string inputString,T *result){ const char *p = inputString.c_str(); char * type = getType(*result); if(type== "int") *result = atoi(p); else if(type== "double") *result = atof(p); else if(type== "float") *result = atof(p); } int main(){ string filePath ="E:\\学习\\机器学习\\Poker_hand\\train.data"; time_t now; now = time(NULL);//设置开始时间 cout<<now<<endl; vector<vector<string>> data = readFile(',',filePath);//读文件 now = time(NULL);//读完时间 cout<<now<<endl; //////////////////将读到的vector<vector<string>>转化为vector<vector<int>>或vector<vector<double>>/////////// vector<vector<int>> intdata; vector<vector<string>>::iterator iter = data.begin(); for(;iter != data.end();iter++){ vector<string> line = *iter; vector<string>::iterator lineiter = line.begin(); vector<int> intline; for(;lineiter != line.end();lineiter++){ int result; transToNum(*lineiter,&result); intline.push_back(result); } intdata.push_back(intline); } ////////////////遍历intdata,输出数值化的数据//////////////////////////////////////////// vector<vector<int>>::iterator intIter = intdata.begin(); for(;intIter != intdata.end();intIter++){ vector<int> line = *intIter; vector<int>::iterator lineiter = line.begin(); for(;lineiter != line.end();lineiter++){ cout<<*lineiter<<" "; } cout<<endl; } return 1;//main }