I would probably start with a little operator to verify the presence of (but otherwise ignore) a string, something like this:
std::istream &operator>>(std::istream &is, char const *pat) {
char ch;
while (isspace(static_cast<unsigned char>(is.peek())))
is.get(ch);
while (*pat && is && *pat == is.peek() && is.get(ch)) {
++pat;
}
// if we didn't reach the end of the pattern, matching failed (mismatch, premature EOF, etc.)
if (*pat) {
is.setstate(std::ios::failbit);
}
return is;
}
We can use this to verify the presence of commas where needed, but otherwise ignore them fairly painlessly. I'd then overload operator>>
for the ROW
type to read the data appropriately:
class ROW {
int year;
enum { MALE, FEMALE} sex;
std::string country;
int foo;
int bar;
friend std::istream &operator>>(std::istream &is, ROW &r) {
is >> r.year >> ",";
std::string s;
is >> s >> ",";
if (s == "MALE")
r.sex = MALE;
else if (s == "FEMALE")
r.sex = FEMALE;
else
error("bad sex");
std::getline(is, r.country, ',');
return is >> r.foo >> "," >> r.bar;
}
};
From there, we can create a vector fairly directly:
// Open the file
std::ifstream in("data.txt");
// Read all the data
std::vector<ROW> rows { std::istream_iterator<ROW>(in), {}};