0

I have a CSV file with data separated with commas. The file looks like this:

1998,MALE,United States,45,566
1993,FEMALE,......

I am going to have a vector of class ROW and each row from the data file will be stored there. My ROW has 5 variables and I need to separate them so I can use set function to row.set(year,sex, country, score, result).

Any idea how to read in the data?

From what I was told I should try to avoid getline. I do not want to convert strings to ints.

Any ideas?

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Using `getline` and convert `string`s to `int`s is actually trivial code to write and it is often much safer to do the conversion yourself so you can better trap bad input. The alternative is teaching the input stream to treat comma as whitespace. Good example here: http://stackoverflow.com/questions/5607589/right-way-to-split-an-stdstring-into-a-vectorstring – user4581301 Sep 22 '16 at 21:55

1 Answers1

1

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), {}};
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • I do not like the operator. A manipulator would be more expressive. –  Sep 23 '16 at 06:53