0

To expand on the title, I am reading a file line-by-line that appears as so:

FirstName,LastName,mm/dd/yyyy,SSN,Role,Salary,Zip,Phone

I have this code I just wrote but am having some trouble placing it into my struct as I'm using std::string as opposed to char[]. I want to continue using std::string for purposes down the road. Also, excuse any syntax errors as I haven't written in c/c++ in a while. I have also read the most elegant way to iterate to words of a string but I am still confused on how to do that with the slashes involved in the date format. SSN and Salary are private members of a struct that will be pushed into a vector for later use. How can I do this using c++ libraries? To be honest, the istringstream confuses me as they include some type of parser inside their struct directly. Is this honestly the best way to accomplish what I'm trying to do?

char stringData[150]; //line to be read in 
while(fgets(stringData, 150, infile) != NULL) {
    if( currentLine == 1) {
        fgets(stringData, 150, infile); //get column names | trash
    }
    else {
        lineSize = sscanf(stringData, "%[^,],%[^,],%d/%d/%d,%d,%[^,],%lf,%[^,],%s", temp.firstName,temp.lastName,
                       &temp.birthMonth,&temp.birthDay,&temp.birthYear, 
                       &tempSSN, temp.role, &tempSalary, temp.zip,
                       temp.phoneNum);

        if(lineSize != 10) { //error message due to a row being incorrect
            cerr << "/* ERROR: WRONG FORMAT OF INPUT(TOO FEW OR TOO MANY ARGUMENTS) ON LINE: */" << currentLine << '\n';
            exit(1);
        }

        temp.setSSN(tempSSN);
        temp.setSalary(tempSalary);
        vector.push_back(temp);//push Employee temp into the vector and repeat loop
    }
    currentLine++
}

TL;DR: What is the easiest way to do this using c++ libraries?

franny
  • 15
  • 5
  • The easiest way to do this is to use a proper CSV parser to extract the individual fields. Then, for specific fields, such as the one that has a date, parse that whole field further and break it down into its components. Implementing two smaller tasks is always easier than trying to implement one huge, complicated task. – Sam Varshavchik Apr 17 '18 at 05:20
  • is the boost library one that you would recommend for this? I discovered it in my research of how to go about this. @SamVarshavchik – franny Apr 17 '18 at 05:21
  • I would also recommend the boost library ... have a look at the boost tokenzier class. You define "," as the separator. – YesThatIsMyName Apr 17 '18 at 06:47

1 Answers1

1

As Sam Varshavchik already mentioned, the easiest way would be separating input with , then separate on of them with / again.

Thanks to this famous question I'm using following approach to split string :

template<typename Out>
void split(const std::string &s, char delim, Out result)
{
    std::stringstream ss(s);
    std::string item;
    while(std::getline(ss, item, delim))
    {
        *(result++) = item;
    }
}

std::vector<std::string> split(const std::string &s, char delim)
{
    std::vector<std::string> elems;
    split(s, delim, std::back_inserter(elems));
    return elems;
}

assuming that this is your structure :

struct info
{
    std::string firstName;
    std::string lastName;
    std::string birthMonth;
    std::string birthDay;
    std::string birthYear;
    std::string tempSSN;
    std::string role;
    std::string tempSalary;
    std::string zip;
    std::string phoneNum;

};

I would implement your needed function like this :

void parser(std::string fileName, std::vector<info> &inf)
{
    std::string line;
    std::ifstream infile(fileName);
    int index = inf.size();
    while(std::getline(infile, line))
    {
        inf.push_back({});
        std::vector<std::string> comma_seprated_vec = split(line, ',');
        inf.at(index).firstName = comma_seprated_vec.at(0);
        inf.at(index).lastName = comma_seprated_vec.at(1);
        inf.at(index).tempSSN = comma_seprated_vec.at(3);
        inf.at(index).role = comma_seprated_vec.at(4);
        inf.at(index).tempSalary = comma_seprated_vec.at(5);
        inf.at(index).zip = comma_seprated_vec.at(6);
        inf.at(index).phoneNum = comma_seprated_vec.at(7);
        std::vector<std::string> slash_seprated_vec = split(comma_seprated_vec.at(2), '/');
        inf.at(index).birthMonth = slash_seprated_vec.at(0);
        inf.at(index).birthDay = slash_seprated_vec.at(1);
        inf.at(index).birthYear = slash_seprated_vec.at(2);
        ++index;
    }
}

Then you can use it like this :

int main()
{
    std::vector<info> information;
    parser("some file", information);

    return 0;
}

There you go, your information are presented in information variable.

HMD
  • 2,202
  • 6
  • 24
  • 37