comma separated stream into struct

2020-05-08 08:05发布

问题:

I have a structure with an int and two strings. When reading in the file it is comma seperated for the first two values and the last value is terminated by a newline. The third argument could be empty however.

ex data: 7, john doe, 123-456-7891 123 fake st.

I want to make it so that my program will grab the first number and put it in the int, find the comma and put the second number in the struct's string etc.

First question is should I use a class instead? I have seen the getline(stream, myString, ','); but my arguments are different data types so I can't just throw them all into a vector.

my code:

struct Person{
    int id;//dont care if this is unique 
    string name;
    string extraInfo;
};

int main(int argc, char* argv[]){
    assert( argc ==2 && "Invalid number of command line arguments");
    ifstream inputFile (argv[1]);
    assert( inputFile.is_open() && "Unable to open file");
}

What is the best way of storing this information and retrieving it from a file that is comma separated for the first two and ends with a newline? I also want the program to ignore blank lines in the file.

回答1:

I'd read the file line-by-line using normal getline(). Then, put it into a stringstream for further parsing or use string's find() functions to split the text manually.

Some more notes:

  • I don't understand your first question about using a class. If you mean for Person, then the answer is that it doesn't matter.
  • Using assert for something you don't have control over is wrong, like argc. This should only be used to verify that you didn't make a programming error. Also, if you #define NDEBUG, the asserts are all gone, so they shouldn't really be part of your program logic. Throw std::runtime_error("failed to open file") instead.
  • You probably don't want the double quotes in your strings. Also, you might want "a,b" to not be split by the comma. Make sure you have tests that assert the required functionality.


回答2:

You can still use the getline approach for tokenising a line, but you first have to read the line:

vector<Person> people;
string line;
int lineNum = 0;

while( getline(inputFile, line) )
{
    istringstream iss(line);
    lineNum++;

    // Try to extract person data from the line.  If successful, ok will be true.
    Person p;
    bool ok = false;

    do {
        string val;
        if( !getline(iss, val, ',') ) break;
        p.id = strtol( val.c_str(), NULL, 10 );

        if( !getline(iss, p.name, ',') ) break;
        if( !getline(iss, p.extraInfo, ',') ) break;

        // Now you can trim the name and extraInfo strings to remove spaces and quotes
        //[todo]

        ok = true;
    } while(false);

    // If all is well, add the person to our people-vector.
    if( ok ) {
        people.push_back(p);
    } else {
        cout << "Failed to parse line " << lineNum << ": " << line << endl;
    }
}


回答3:

Once you get the line in string using getline, use strtok.

char myline[] = "7, john doe, 123-456-7891 123 fake st.";
char tokens = strtok(myline, ",");
while(tokens)
{
    //store tokens in your struct values here
}

You'll need to include #include <string.h> to use strtok