c++ifstreamformatted-input

C++: reading from txt file with multiple delimeter


Is there any way to read from file containing student records but delimited by different characters? My text is as below:

125 {John_BROWN_Biology} {100_81}
245 {Amanda_SMITH_Chemistry} {83_74}
436 {Michael_CLARK_Calculus} {35_48}

I have to store the in separate arrays so that I can calculate their average and put in ascending order. I have written the code in C++ in this way:

int rank;
char st_info[SIZE];
int grades[SIZE];
bool success1 = false;
bool success2 = false;
bool success3 = false;

ifstream inFile;
inFile.open("records.txt");
string line;
int i=0, j=0;
while (!inFile.getline(rank, 30, '{').eof){
    inFile.getline(st_info, SIZE, '_');
    inFile.getline(words_array, SIZE, '_');
}
while (!success1)
{
    getline(inFile,Line,'{'); // get values for info array
    stringstream iss1; 
    iss1 << Line; //Put the string into a stream
    iss1 >> rank; //To send data as an int.
    cout << "STUDENT NUMBER:" << rank << "  ";
    while (!success2){
    // for the info in {} part
        getline(inFile,Line,'_'); 
        stringstream iss; 
        iss << Line; 
        iss >> st_info[i];
        cout <<"STUDENT INFO:" << st_info[i] << "   ";
        i++;
        if (getline(inFile,Line,'}')){
            stringstream iss2; 
            iss2 << Line; 
            iss2 >> st_info[i];
            cout << st_info[i] << " ";
            i=0;
            success2 = true;
        }
    }
    getline(inFile,Line,'{'); 
    stringstream iss3; 
    iss3 << Line; 
    iss3 >> grades[j]; 
    cout << "GRADES: "<< grades[i] << " ";
    j++;
    while (!success3){
        getline(inFile,Line,'_');
        stringstream iss4; 
        iss4 << Line;
        iss4 >> grades[j];
        cout << grades[i] << "  ";
        j++;
        if (getline(inFile,Line,'}')){
            stringstream iss5; 
            iss5 << Line;
            iss5 >> grades[j];
            cout << grades[i] << "  ";
            j=0;
            success3 = true;
        }
    }
} 

However, as an output I am getting:

1 J 100
2 A 100
4 M 100

Tried to fix, but it get worse. Anybody who can help? Thanks in advance.


Solution

  • There are several issues with your approach and your code:

    I propose you therefore to use the following skeleton, that reads the file line by line, and parses each line separately using a stringstream. Note that I only use the non-member variant of getline() to read strings instead of arrays of char (this frees me from thinking of buffer overflows):

    ...
    char delim;  
    int rank;
    string names, grades;
    string line;
    
    while (getline(inFile, line))   // read line by line 
    {
        stringstream sst{line};     // then parse the line using a string stream
    
        sst>>rank;                  // read an integer
        sst>>delim;                 // skip white and read a single char 
        if (delim!='{') {
            cout<<"Error on line: { expected for name instead of "<<delim<<endl; 
            continue;   // next line, please !! 
        }
        getline(sst,names, '}');  // TO DO: error handling
        sst>>delim; 
        if (delim!='{') {
            cout<<"Error on line: { expected for grades instead of "<<delim<<endl; 
            continue;   // next line, please !! 
        }
        getline(sst,grades, '}');  // TO DO: additional error handling
    
        cout << rank<<" "<<names<<" "<<grades<<endl; // temporary:  
    
        // TO DO: parse names and grades by using further stringstreams 
    } 
    

    Online demo

    Note that I used a simple parsing approach: read a char and check it matches the expected opening character, and use getline() to read until the closing character (the latter being consumed but excluded from the string). This doesn't allow for nested {...} in your format.