c++ - How can I read a file with lines of different number of numbers -
i trying read in file of data, approx 2000 lines, file looks like
1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5
there blank (white space) , 1.3/1.7 in same column
the way have setup storing vector of structs where
struct num { double d1, d2, d3, d4, d5; };
what trying achieve is
num a; vector<num> data (int = 0; < 4; i++) { file >> a.d1 >> a.d2 >> a.d3 >> a.d4 >> a.d5; data.push_back(a); }
and find logic recognize blank space in second line , store d1=1.6, d2=0, d3=1.7 etc.. , third line d1=2.0 , d2,d3,d4,d5=0 confused on how test/get logic implementing this, if possible in c++ vs2010 after looking @ first answer thought should provide more info, each line in file belongs satellite, , each number represents observation on specific wavelength, if blank means has no observations on wavelength.
so elaborate, first line represents satellite 1 has observation on 5 wavelengths, line 2 reprsents satelittle 2 , has observations on wavelength 1,3,4,5 , none on wavelength 4.
thats why trying break each line seperate struct, because each line seperate satellite
observing data:
- every data point stored in following pattern: data, space.
- if data point doesn't exist, represented space, unless last non-existent data point other output truncated newline.
this came with:
#include <fstream> #include <iostream> #include <string> #include <vector> #include <cstdlib> #include <sstream> #include <iomanip> #include <cctype> using namespace std; //note lines stored newlines @ end of them. //this merely artifact of methodology using, //as newline flag truncates output (as per problem) vector<string> preparse_input(const std::string& filename) { vector<string> lines; ifstream ifile; ifile.open(filename.c_str(), ios::in); if (!ifile.is_open()) { exit(1); } string temp, chars, line; char ch; while(getline(ifile, temp)) { temp += "\n";//getline removes newline: because need it, reinsert istringstream iss(temp); //first read in line char char while(iss >> noskipws >> ch) { chars += ch; } bool replaced_newline = false; int nargs = 0; //i have used iterators here, imo, way easier read. modify if need be. (int = 0; < chars.size(); ++i) { if (isdigit(chars[i]) && chars[i+1] == ' ') { nargs += 1; } else if(isspace(chars[i]) && isspace(chars[i+1])) { if (chars[i+1] == '\n') { replaced_newline = true; } //this means there no value set //hence, set value 0 value part: chars[i+1] = '0'; line += chars[i]; ++i;//now, skip next character since 1 spacing, other value nargs += 1; } //now rebuild line: line += chars[i]; if(isdigit(chars[i]) && chars[i+1] == '\n') { nargs += 1; //check nargs: (int = nargs; < 5; ++i) { line += " 0"; nargs += 1; } } if (replaced_newline) { line += '\n'; } replaced_newline = false; } lines.push_back(line); chars.clear(); line.clear(); } ifile.close(); return lines; } //this way, it's easier adapt type of input may have template <typename t> vector< vector<t> > parse_input (const vector<string>& lines) { vector< vector<t> > values; t val = 0; for(vector<string>::const_iterator = lines.begin(); != lines.end(); ++it) { vector<t> line; istringstream iss(*it); string temp; while(getline(iss, temp, ' ')) { if (istringstream(temp) >> val) { line.push_back(val); } else { line.push_back(0);//this value badly parsed values set to. //you have option of setting sentinel value, -1, can go , correct later on, if need be. depending on how want treat error - hard or soft (stop program execution vs adapt , continue parsing), can adapt accordingly //i opted treat soft error without sentinel value - set 0 (-1 more applicable in general case), , informed user error occurred //the flipside of have treated hard error , have `exit(2)` (or whatever error code wish set). cerr << "there problem storing:\"" << temp << "\"\n"; } } values.push_back(line); } return values; } int main() { string filename = "data.dat"; vector<string> lines = preparse_input(filename); vector < vector<double> > values = parse_input<double>(lines); (int = 0; < values.size(); ++i) { (int j = 0; j < values[i].size(); ++j) { cout << values[i][j] << " "; } cout << endl; } return 0; }
summarily, broke down string reading each line character character, , rebuilding each line replacing blanks 0
easier parsing. why? because without value that, there no way tell parameter stored or skipped (using default ifstream_object >> type
methodology).
this way, if use stringstream
objects parse input can correctly determine parameter set, or not set; then, store results , dandy. desire.
and, using on following data:
1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0 2.0 2.1 2.2 2.3 2.4 2.5 2.1 2.4
gives output:
1.1 1.2 1.3 1.4 1.5 1.6 0 1.7 1.8 1.9 2 0 0 0 0 2 0 0 0 0 2.1 2.2 2.3 2.4 2.5 2.1 0 0 2.4 0
note: line 3 has 8 spaces (1 no data , 1 spacing). line 4 line original data. line 6 contains 5 spaces (following pattern cited).
lastly, let me this far, 1 of insane methods of storing data i've ever encountered.
Comments
Post a Comment