Home > Back-end >  Reading integers and strings from a text file and storing in parallel arrays
Reading integers and strings from a text file and storing in parallel arrays

Time:07-11

I have a text file that stores the index, student name and student ID and I am trying to read them into an array of integers index, arrays of strings studentName and studentID. I'm having problems storing the student's names because they could be more than a single word. I could separate the items in the text file by commas and use getline but that would mean the index array will have to be a string type. Is there a workaround for this without changing the original text file?

Original file:

1 James Smith E2831
2 Mohammad bin Rahman M3814
3 MJ J4790

const int SIZE = 3;
int index[SIZE];
string studentName[SIZE], studentID[SIZE];
fstream infile("students.txt");

if(infile.is_open()){
    int i = 0;
    while(i < 3){
        infile >> index[i] >> studentName[i] >> studentID[i];
        i  ;
    }
}

Changed file:

1,James Smith,E2831
2,Mohammad bin Rahman,M3814
3,MJ,J4790
const int SIZE = 3;
string index[SIZE];
string studentName[SIZE], studentID[SIZE];
fstream infile("students.txt");

if(infile.is_open()){
    int i = 0;
    while(i < 3){
        getline(infile, index[i],',');     //index array is string
        getline(infile, studentName[i],',');
        getline(infile, studentID[i],'\n');
        i  ;
    }
}

CodePudding user response:

It's an error to read one line into one student property with the given input format. You need to read one line and then split the information in this line into the 3 properties.

std::stoi can be used to convert to convert the first part of the line read to an int. Futhermore it's simpler to handle the data, if you create a custom type storing all 3 properties of a student instead of storing the information in 3 arrays.

Note that the following code requires the addition of logic to skip whitespace directly after (or perhaps even before) the ',' chars. Currently it simply includes the whitespace in the name/id. I'll leave that task to you.

struct Student
{
    int m_index;
    std::string m_name;
    std::string m_id;
};

std::vector<Student> readStudents(std::istream& input)
{
    std::vector<Student> result;

    std::string line;
    while (std::getline(input, line))
    {
        size_t endIndex = 0;
        auto index = std::stoi(line, &endIndex);
        if (line[endIndex] != ',')
        {
            throw std::runtime_error("invalid input formatting");
        }
          endIndex;
        auto endName = line.find(',', endIndex);
        if (endName == std::string::npos)
        {
            throw std::runtime_error("invalid input formatting");
        }
        result.push_back(Student{ index, line.substr(endIndex, endName - endIndex), line.substr(endName   1) });
    }

    return result;
}

int main() {
    std::istringstream ss(
        "1,James Smith,E2831\n"
        "2, Mohammad bin Rahman, M3814\n"
        "3, MJ, J4790\n");

    auto students = readStudents(ss);

    for (auto& student : students)
    {
        std::cout << "Index=" << student.m_index << "; Name=" << student.m_name << ";Id=" << student.m_id << '\n';
    }
}

CodePudding user response:

There are so many possible solutions that it is hard to tell, what should be used. Depends a little bit on your personal style and how good you know the language.

In nearly all solutions you would (for safety reasons) read a complete line with std::getline then put either split the line manually or use a std::istringstream for further extraction.

A csv input would be preferred, because it is more clear what belongs together.

So, what are the main possibilities? First the space separated names

  • You could use a std::regexand then search or match for example "(\d) ([\w ] ) (\w )"
  • You cou create substrings, by searching the first space from the right side of the string, which would be the "studentID", then the getting the rest is simple
  • You could use a while loop and read all parts of the string and put it in a std::vector. The first element in the std::vector is then the index, the last the ID and the rest would be the name.
  • You could parse the string with formatted input functions. First read the index as number, then the rest as stringm the split of the last part and get the id.

And many more

For csv, you could use

  • the std::sregex_token_iterator looking for the comma as separator
  • Use also a std::vector and later pick the needed values.
  • Use a mixture of formatted and unformatted input

Example:

std::getline(std::getline(infile >> index >> Comma >> std::ws, name, ','), id);

It is up to you, what you would like to implement.

Write your preference in the comment, then I will add some code.

  • Related