做數據處理時經常會用讀這樣的文本文件:
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 }