I have a file that contains employee information on each line (id, department, salary, and name). Here is an example line:
45678 25 86400 Doe, John A.
Right now I am reading in each word using fstream, which works until I get to the name part. My question is what is the easiest way to capture that name as a whole?
Data >> Word;
while(Data.good())
{
//blah blah storing them into a node
Data >> Word;
}
You probably want to define a struct to hold the data for an employee, the define an overload of operator>> to read one of those records from your file:
struct employee {
int id;
int department;
double salary;
std::string name;
friend std::istream &operator>>(std::istream &is, employee &e) {
is >> e.id >> e.department >> e.salary;
return std::getline(is, e.name);
}
};
int main() {
std::ifstream infile("employees.txt");
std::vector<employee> employees((std::istream_iterator<employee>(infile)),
std::istream_iterator<employee>());
// Now all the data is in the employees vector.
}
#include <fstream>
#include <iostream>
int main() {
std::ifstream in("input");
std::string s;
struct Record { int id, dept, sal; std::string name; };
Record r;
in >> r.id >> r.dept >> r.sal;
in.ignore(256, ' ');
getline(in, r.name);
std::cout << r.name << std::endl;
return 0;
}
I would create a record and define the input operator
class Employee
{
int id;
int department;
int salary;
std::string name;
friend std::istream& operator>>(std::istream& str, Employee& dst)
{
str >> dst.id >> dst.department >> dst.salary;
std::getline(str, dst.name); // Read to the end of line
return str;
}
};
int main()
{
Employee e;
while(std::cin >> e)
{
// Word with employee
}
}
Related
This question already has an answer here:
Read lines from text file and store into array
(1 answer)
Closed 1 year ago.
the text file looks something like this:
9528961 Adney Smith CS 4.2
9420104 Annalynn Jones EE 2.6
9650459 Bernadette Williams IT 3.6
...
there are 45 lines in the text file meaning 45 students. I have read the text file and when I run the program I get this:
9428167
Mason
Taylor
CS
4.8
9231599
Alexander
Jones
CS
2.3
My main file looks like this:
int main()
{
auto student = new Student<string>();
std::vector<string> students;
std::ifstream inputFile;
inputFile.open("enroll_assg.txt");
std::string line;
if(inputFile.is_open()){
while(std::getline(inputFile, line)){
std::istringstream iss(line);
std::string word;
while(iss >> word){
std::cout << word << std::endl;
for(int i = 0; i < 5; i++){
}
}
}
}
return 0;
}
Each student has 5 columns (id, fname, lname, department, gpa) and I need make a vector which includes all these student object. I need some help doing this so comments and answers are most welcome. Thank you.
IMHO, the best method is to use a struct or class to model or represent the data record you need to read.
struct Student
{
unsigned int id;
std::string first_name;
std::string last_name;
std::string major_code;
double gpa;
friend std::istream& operator>>(std::istream& input, Student& s);
};
std::istream& operator>>(std::istream& input, Student& s)
{
input >> s.id;
input >> s.first_name;
input >> s.last_name;
input >> s.major_code;
input >> s.gpa;
input.ignore(10000, '\n'); // Synchronize to next line.
return input;
}
Your input code could look like this:
std::vector<Student> database;
Student s;
//... open file.
while (student_file >> s)
{
database.push_back(s);
}
The above code will read each student record into a database, so you can analyze it.
Try something more like this instead:
int main()
{
std::ifstream inputFile("enroll_assg.txt");
if (inputFile.is_open()){
std::vector<Student<string>> students;
std::string line;
while (std::getline(inputFile, line)){
std::istringstream iss(line);
Student<string> student;
iss >> student.id;
iss >> student.fname;
iss >> student.lname;
iss >> student.department;
iss >> student.gpa;
students.push_back(student);
}
// use students as needed...
}
return 0;
}
Then, you should consider having Student overload the operator>>, which will greatly simplify the loop so you can do something more like this instead:
template<typename T>
std::ostream& operator>>(std::ostream &in, Student<T> &student)
{
std::string line;
if (std::getline(in, line))
{
std::istringstream iss(line);
iss >> student.id;
iss >> student.fname;
iss >> student.lname;
iss >> student.department;
iss >> student.gpa;
}
return in;
}
int main()
{
std::ifstream inputFile("enroll_assg.txt");
if (inputFile.is_open()){
std::vector<Student<string>> students;
Student<string> student;
while (inputFile >> student){
students.push_back(student);
}
// use students as needed...
}
return 0;
}
First this question is a duplicate of Read lines from text file and store into array which already has the answer you're looking for in this question.
The below shown program uses struct to represent a given Student and it also used a std::vector. You can use this program as a reference(starting point). It reads student information from the input text file and store that information in a vector of Student.
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
//this class represents a Student
class Student
{
public:
std::string firstName, lastName, courseName ;
unsigned long id = 0;
float marks = 0;
};
int main()
{
std::ifstream inputFile("input.txt");
std::string line;
std::vector<Student> myVec;//create a vector of Student objects
if(inputFile)
{
while(std::getline(inputFile, line))
{
Student studentObject;
std::istringstream ss(line);
//read the id
ss >> studentObject.id;
//read the firstname
ss >> studentObject.firstName;
//read the lastname
ss >> studentObject.lastName;
//read the courseName
ss >> studentObject.courseName;
//read the marks
ss >> studentObject.marks;
if(ss)//check if input succeded
{
myVec.emplace_back(studentObject);//add the studentObject into the vector
}
}
}
else
{
std::cout<<"File cannot be opened"<<std::endl;
}
//lets print out the elements of the vecotr to confirm that all the students were correctly read
for(const Student &elem: myVec)
{
std::cout << elem.id << ": "<<elem.firstName<<" "<<elem.lastName<<" "<<elem.courseName<<" "<<elem.marks <<std::endl;
}
return 0;
}
The output of the above program can be seen here.
Suppose I have a struct like this:
struct Person
{
string fName;
string lName;
int age;
};
And I want to read in a file(ppl.log) like this:
Glenallen Mixon 14
Bobson Dugnutt 41
Tim Sandaele 11
How would I read in the file and store them?
This is what I have
int main()
{
Person p1, p2, p3;
ifstream fin;
fin.open("ppl.log");
fin >> p1;
fin >> p2;
fin >> p3;
return 0;
}
Does that read in the entire line? Or do I have to use the getline()?
I recommend overloading operator>>:
struct Person
{
string fName;
string lName;
int age;
friend std::istream& operator>>(std::istream& input, Person& p);
};
std::istream& operator>>(std::istream& input, Person& p)
{
input >> p.fName;
input >> p.lName;
input >> p.age;
input.ignore(10000, '\n'); // Align to next record.
return input;
}
This allows you to do things like this:
std::vector<Person> database;
Person p;
//...
while (fin >> p)
{
database.push_back(p);
}
Your fields are space separated, so you don't need to use getline. The operator>> for strings will read until a whitespace character.
How do I stream a line of comma separated txt file to an object that contain first name, last name and age variables? I want to overload the >> operator to do such operations.
std::istream& operator>>(std::istream& file, PersonData& obj) {
std::string line, firstName, lastName, age;
while (std::getline(file, line)) {
std::stringstream ss(line);
std::getline(ss,firstName,',');
std::getline(ss,lastName,',');
std::getline(ss, age,',');
firstName >> obj.firstName;
lastName >> obj.lastName;
std::stoi(age) >> obj.age;
}
return file;
}
Your operator>> should read a single entry from the file.
If you have a class
struct Person {
std::string first_name;
std::string last_name;
unsigned age;
};
You can use in/output operators:
std::ostream& operator<<(std::ostream& out,const Person& p) {
out << p.first_name << ", " << p.last_name << ", " << p.age;
return out;
}
std::istream& operator>>(std::istream& in,Person& p){
const auto comma = ',';
std::getline(in,p.first_name,comma);
std::getline(in,p.last_name,comma);
std::string temp;
std::getline(in,temp);
p.age = std::stoi(temp);
return in;
}
And then extract one Person at a time from the file:
int main() {
std::stringstream ss{"Peter, Fish, 42\nLaura, Peterson, 105"};
Person p1,p2;
ss >> p1 >> p2;
std::cout << p1 << "\n" << p2;
};
Output:
Peter, Fish, 42
Laura, Peterson, 105
Live example
To read all entries from a file you can use a vector and a loop:
std::vector<Person> persons;
Person entry;
while(stream >> entry) persons.push_back(entry);
PS: I missed to remove leading blanks from the names. I'll leave that to you ;)
john-wick.txt
John,Wick,50
main.cpp
#include <iostream>
#include <fstream>
struct PersonData {
string firstname;
string lastname;
int age;
friend std::istream& operator>>(std::istream& in, PersonData& obj) {
char comma;
in >> obj.firstname >> comma >> obj.lastname >> comma >> obj.age;
return in;
}
}
int main(int argc, char *argv[]) {
std::ifstream file("john-wick.txt");
PersonData john;
file >> john;
}
Here's a stencil for your class:
class My_Class
{
public:
friend std::istream& operator>>(std::istream& input, My_Class& mc);
private:
// members go here.
};
std::istream& operator>>(std::istream& input, My_Class& mc)
{
// Insert code to read comma separated values here.
return input;
}
The above allows you to stream input to your class:
My_Class mc;
std::vector<My_Class> database;
while (input_file >> mc)
{
database.push_back(mc);
}
Edit 1: Reading CSV
Based on the code you posted, I believe this is what you want:
std::istream& operator>>(std::istream& input, My_Class& mc)
{
std::getline(input, mc.firstName,',');
std::getline(input, mc.lastName,',');
input >> mc.age;
// Ignore till the end of the line:
input.ignore(10000, '\n');
return input;
}
Editing your question with a sample of the input file will allow readers to confirm or deny the content of the function.
Please someone clarify the issue I am having right now with user input in C++ [VS 2015].
I have a simple class StudentEntry
const int MAX_STUDENT = 50;
int entryCount = -1;
class StudentEntry {
public:
StudentEntry(const std::string &s, std::vector<int> li) : name(s), marks(li) {}
private:
std::string name;
std::vector<int> marks;
}
* entryList[MAX_STUDENT];
Two non-member functions ask user to input name [string] and marks [vector<int>]:
std::string getName() {
std::string input;
std::cout << "Enter student name: ";
std::cin >> input;
return input;
}
std::vector<int> getMarks() {
std::string line;
int number;
std::vector<int> input;
std::cout << "Enter student marks separated by spaces: ";
getline(std::cin, line);
std::istringstream ss(line);
while (ss >> number) {
input.push_back(number);
}
return input;
}
My goal is to add a new entry using a function like addRecord(). What I plan to do, is:
int main()
{
std::string in_name = getName();
std::vector<int> in_marks = getMarks();
entryList[entryCount] = new StudentEntry(in_name, in_marks);
...
}
However, I can't read a vector from user input. Basically, if I comment the line
std::string in_name = getName();
I can enter some marks and get them saved into in_marks. But after I read the in_name, the in_marks vector is not being read from the prompt.
Why is this happening?
I have a project in my C++ class - we're supposed to make a "simple student management system" comprised of a class for the student attribute variables, and a main function with a branch statement that lets the user input names and IDs for the students. I know that I need to use an array to make "slots" for the students, and that my branch statements need to let the user input values into those slots, but I'm not exactly sure how to do it. Here is the code that I have so far.
#include <string>
#include <iostream>
#include <utility>
using std::string;
using std::cin;
using std::cout;
using std::endl;
struct Student {
private:
int id;
string name;
int birthday;
public:
Student()
{
id = 0;
birthday = 0;
}
Student(int id, string name, int birthday)
{
//set your parameters to the class variables
this->id = id;
this->name = name;
this->birthday = birthday;
}
void setID(int id)
{
this->id = id;
}
int getID() {
return id;
}
void setName(string name)
{
this->name = name;
}
string getName()
{
return name;
}
void setBirthday(int birthday)
{
this->birthday = birthday;
}
int getBirthday()
{
return birthday;
}
void output() {
cout << id << name << birthday << endl;
}
};
int main() {
Student arr[50];
cout << "Student Management System" << endl;
cout << "Press 'a' to add a student" << endl;
char a = 1;
int y = 1;
while (a == 'a') {
switch (y)
{
cout << "Input Student ID:";
cin >> id;
}
}
}
What I'm focusing on most is the fourth line from the bottom. I was told that I need to use my setters, so I said that I want what my user inputs to be treated as the value of the ID variable that I set in the class. However, when I wrote this out, I was given an error. Could someone tell me what the issue is?
You should try to get your switch statement working correctly. To use classes setters, you can store the user input to a temporary variable then from your one student you can call the member function. i.e. in your case:
arr[index].setID(tempInputVariable);
There is no id in your main function or as a global variable.
I suggest you overload operator >> to have your structure extract its members from the data stream:
struct Student
{
//...
public:
friend std::istream& operator>>(std::istream& input, Student& s);
};
std::istream& operator>>(std::istream& input, Student& s)
{
input >> s.id;
input >> s.name;
input >> s.birthday;
return input;
}
Although the above code doesn't use setters, it is the preferred method for inputting data.
The overload can be modified to use setters (kind of overkill):
std::istream& operator>>(std::istream& input, Student& s)
{
int id;
input >> id;
s.setID(id);
std::string name;
input >> name;
s.setName(name);
int birthday;
input >> birthday;
s.setBirthday(birthday);
return input;
}
If you don't like the overload, you can perform the steps in your main function:
//...
Student new_student;
//...
{
int student_id;
std::cout << "Input Student ID:";
std::cin >> student_id;
new_student.setID(student_id);
std::string student_name;
std::cout << "Input Student Name: ";
std::cin >> student_name;
new_student.setName(student_name);
int student_birthday;
std::cout << "Input Student Birthday: ";
std::cin >> student_birthday;
new_student.setBirthday(student_birthday);
}
Edit 1: The Database
You'll probably need to store or remember the students. This is easy using the first method above:
std::vector<Student> database;
Student s;
std::cout << "Enter student information (ID, Name and birthday, separated by spaces:\n";
std::cin >> s;
// Append to the database
database.push_back(s);
If you haven't learned std::vector you can try an array:
const size_t MAXIMUM_STUDENTS = 16;
Student database[MAXIMUM_STUDENTS];
size_t database_index = 0;
//...
Student s;
std::cout << "Enter student information (ID, Name and birthday, separated by spaces:\n";
std::cin >> s;
// Append to database
database[database_index] = s;
++database_index;