做資料處理時經常會用讀這樣的文字檔:
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}