简体   繁体   中英

c++ read in multiple lines, varied delimiters

The input file is structured like:

First Last,33,Male,city
score1,15/30
score2, 20/20

First Last,43,Female,city
score1,20/20
score2,18/20

with an unknown number of records, each separated by a blank line. Each record becomes an object to be stored in a dynamic array object (which is confusing in its own right).

I can place the first line into variables, but the remaining lines are lost in the ether. Although it produces the proper number of records (in this case, it would be 2), each record is filled with the first line's data and no scores.

I just have no ideas about how to read it in properly, and still don't know how to deal with that blank line in between each record. This was for a previous homework for which I cannot get a straight answer out of anybody, and would love to know, since reading in from files seems to be all the rage...

Here is what I have:

std::ifstream read_data(data_file);
std::string line;

while(std::getline(read_data, line))
{
     std::stringstream ss(line);
     char detectNewline;

     getline(ss, tempName, ',');
     getline(ss, tempAgeString, ',');
     tempAge = std::atoi(tempAgeString.c_str());
     getline(ss, tempGender, ',');
     getline(ss, tempCity, '\n';

           for(int i=0; i < 2; i++)  // I am not married to this idea, seems efficient
           {
                getline(ss, tempScore, ',');
                getline(ss, pointsEarnedHolder, '/');
                tempPointsEarned += std::atof(pointsEarnedHolder.c_str());
                getline(ss, totalPointsHolder, '\n');
                tempTotalPoints += std::atof(totalPointsHolder.c_str());
           }

           // variable manipulation

           ClassName object(proper vars);
           previouslyDeclaredDynamicArrayObject(object);

           detectNewline = read_data.peek();
           if(detectNewline == '\n')
           {
              std::cin.ignore();
           }

} //while

Thank you for any insight!

I will touch on a way to read the information efficiently.

First you can getline the first line and parse the information like you have. Then you will parse the information provided in the scores until getline hits a blank line. Then once this happens you will add the object into the array, and get the starting information for the next object and then repeat the process.

The code would look similar to this (pretty pseudo-y):

 std::getline(read_data, line); while( !read_data.eof() ) { std::stringstream ss(line); getline(ss, tempName, ','); getline(ss, tempAgeString, ','); tempAge = std::atoi(tempAgeString.c_str()); getline(ss, tempGender, ','); getline(ss, tempCity, '\\n'; std::getline( read_data, line ) while( line != "\\n" ) { getline(ss, tempScore, ','); getline(ss, pointsEarnedHolder, '/'); tempPointsEarned += std::atof(pointsEarnedHolder.c_str()); getline(ss, totalPointsHolder, '\\n'); tempTotalPoints += std::atof(totalPointsHolder.c_str()); std::getline( read_data, line ) } // variable manipulation ClassName object(proper vars); previouslyDeclaredDynamicArrayObject(object); std::getline(read_data, line); } //while 

This is assuming that you are properly extracting the information from the lines.

An easier way to delimit upon those characters is to classify them as whitespace through the std::ctype<> facet of the streams locale. Then you can simply use the extractor operator>>() instead of parsing through the unformatted functions.

Here's an example of how to set the facet:

struct ctype : std::ctype<char>
{
    static mask* make_table()
    {
        const mask* table = classic_table();
        static std::vector<mask> v(table, table + table_size);
        v[' '] |= space;
        v[','] |= space;
        v['/'] |= space;
        return &v[0];
    }

    ctype() : std::ctype<char>(make_table()) { }
};

You can then make a convience function to install it into the stream's locale:

std::istream& custom_ctype(std::istream& is)
{
    is.imbue(std::locale(is.getloc(), new ctype));
    return *is;
}

// ...
file >> custom_ctype;

After that it becomes simple to extract characters from the file into variables. Just think of the characters that you want to ignore as if they were the space character or the newline character, because that's exactly what we've done here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM