getline() outputting extra whitespace after certain objects

I am creating a program for my class project that reads in a string text file, parses the data into objects then stores into a vector. The file is simply a course number, name, and any prerequisites of the course (if they have any) -- EXAMPLE: CSCI350,Operating Systems,CSCI300

I am running into a bit of a snag when it comes to displaying all of the courses and have not been able to find a solution. There are two courses that do not have any prerequisites, and when printing the sample schedule a new line is added right after each of those courses. I believe the issue lies either within the prerequisites vector or my getline().
If anyone could explain to me what I am doing wrong that would be lovely, as I am learning on my own. Any help or tips are greatly appreciated and thank you in advance. I included my print functions for the sample schedule and for reference my function to print just prerequisites.

OUTPUT EXAMPLE:
MATH201, Discrete Mathematics //Space below this

CSCI300, Introduction to Algorithms
CSCI350, Operating Systems
CSCI101, Introduction to Programming in C++
CSCI100, Introduction to Computer Science //Space below this

CSCI301, Advanced Programming in C++
CSCI400, Large Software Development
CSCI200, Data Structures

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
  struct Course {
	string courseNumber;
	string name;
	vector<string> prerequisites;
};

vector<Course> loadAndParseData() {
	ifstream inFS("abcu.txt");
	string line; 

	vector<Course> courses; 

	while (getline(inFS, line)) {
		istringstream iss(line); 
		string substring;
		vector<string> substrings;
		while (getline(iss, substring, ',')) { 
			substrings.push_back(substring);
		}
		Course course; 
		course.courseNumber = substrings[0];
		course.name = substrings[1];
		// //Adds prerequisites
		for (int i = 2; i < substrings.size(); ++i) {
			course.prerequisites.push_back(substrings[i]);
		}
		courses.push_back(course); //Adds course to vector
	}
	inFS.close();
	return courses;
}

void printSampleSchedule(vector<Course> courses) {
	cout << "Here is a sample schedule:" << endl;
	for (int i = 0; i < courses.size(); ++i) {
		cout << courses[i].courseNumber << ", " << courses[i].name << endl;
	}
}

void printPrerequisites(Course course) {
	vector<string> prerequisites = course.prerequisites;

	cout << "Prerequisites: ";
	for (int i = 0; i < prerequisites.size(); ++i) {
		cout << prerequisites[i] << ",";
	}
}
Last edited on
As a possible starting point, consider. This will read and parse the file and display the read data:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <fstream>

struct Course {
	std::string courseNumber;
	std::string name;
	std::vector<std::string> prerequisites;
};

std::vector<Course> loadAndParseData() {
	std::ifstream inFS("abcu.txt");
	std::vector<Course> courses;

	if (!inFS)
		return ("Cannot open file\n"), courses;

	for (std::string line; std::getline(inFS, line); ) {
		std::istringstream iss(line);
		std::vector<std::string> substrings;

		for (std::string substring; std::getline(iss, substring, ','); substrings.push_back(substring));
		if (substrings.size() >= 2) {
			Course course;

			course.courseNumber = substrings[0];
			course.name = substrings[1];

			for (size_t i {2}; i < substrings.size(); ++i)
				course.prerequisites.push_back(substrings[i]);

			courses.push_back(course);
		}
	}

	return courses;
}

void printPrerequisites(const Course& course) {
	//std::cout << "Prerequisites: ";

	for (size_t i {}; i < course.prerequisites.size(); ++i)
		std::cout << ',' << course.prerequisites[i];
}

void printSampleSchedule(const std::vector<Course>& courses) {
	std::cout << "Here is a sample schedule:\n";

	for (size_t i {}; i < courses.size(); ++i) {
		std::cout << courses[i].courseNumber << ", " << courses[i].name;

		if (!courses[i].prerequisites.empty())
			printPrerequisites(courses[i]);

		std::cout << '\n';
	}
}

int main() {
	const auto data {loadAndParseData()};

	printSampleSchedule(data);
}


Input file:

CSCI350,Operating Systems,CSCI30
qwe,asdf,lkh,lkj
eet,lkj
qwe,lkj
asd fg,lkj lk,poi


Displays:


Here is a sample schedule:
CSCI350, Operating Systems,CSCI30
qwe, asdf,lkh,lkj
eet, lkj
qwe, lkj
asd fg, lkj lk,poi

Thank you so much for helping! I tried implementing this into my code, but I am still getting the same result. I wish we didn't have to use namespace std, but that is how we are taught so we have to :/

I put how I have the main parsing function currently which behaves the way I need it to besides the spaces still. I tried nesting the last for and if statements inside of for (string substring; getline(iss, substring, ','); substrings.push_back(substring)); which got rid of the spaces, but then it erases the course objects with no prerequisites and repeats two other courses instead.

Not sure if it's relevant, but I do have a switch case in my main() to take in input and respond accordingly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 vector<Course> loadAndParseData() {
	ifstream inFS("abcu.txt");

	vector<Course> courses; 

	if (!inFS) {
		cout << "Cannot open file.\n";
	}

	for (string line; getline(inFS, line); ) {
		istringstream iss(line);
		vector<string> substrings;

		for (string substring; getline(iss, substring, ','); substrings.push_back(substring));
		if (substrings.size() >= 2) {
			Course course;

			course.courseNumber =substrings[0];
			course.name = substrings[1];

			for (int i = 2; i < substrings.size(); ++i) {
				course.prerequisites.push_back(substrings[i]);
			}
			courses.push_back(course);
		}
	}
	return courses;
}
Would you post your input file that shows the issues.
This is the file given to us for input:
MATH201,Discrete Mathematics
CSCI300,Introduction to Algorithms,CSCI200,MATH201
CSCI350,Operating Systems,CSCI300
CSCI101,Introduction to Programming in C++,CSCI100
CSCI100,Introduction to Computer Science
CSCI301,Advanced Programming in C++,CSCI101
CSCI400,Large Software Development,CSCI301,CSCI350
CSCI200,Data Structures,CSCI101

I was messing around with it a bunch last night and was thinking that maybe because the first line read in doesn't contain any prerequisites that it could possibly be throwing off initialization in the prerequisites vector. I also thought this because I have a function that searches for a course number and will return the name and prerequisites. Every course returns correctly besides MATH201 which doesn't return anything, UNLESS I change it's position in the text file (which is not allowed, I just tried for testing). However, this still doesn't fix the extra line issue with MATH201 and CSCI100.

I really appreciate you tackling this with me. I feel so defeated.

EDIT:
I feel stupid. I think it was my text file all along. I deleted the file and started over by resaving it, which this time my computer saved it as a .rtf file. This file is outputting everything correctly so I am not sure what the issue was. The user has to type in the file name, and if I put both the .txt file and the .rtf file in the project source folder, the only one that reads in is the .rtf file. Is the file outputting correctly for you on your computer no matter the file extension?
Last edited on
Yes. The extension makes no difference. My code from above displays the data as expected and if L54-55 are commented, I get the output:


Here is a sample schedule:
MATH201, Discrete Mathematics
CSCI300, Introduction to Algorithms
CSCI350, Operating Systems
CSCI101, Introduction to Programming in C++
CSCI100, Introduction to Computer Science
CSCI301, Advanced Programming in C++
CSCI400, Large Software Development
CSCI200, Data Structures


as expected.

I wondered if it was a problem with the input file, that's why I asked for the data to be posted.

How is the data file produced? Is it created by a program or do you input the data into a text editor and then save the contents? How does the file get the extension .rtf (which means Rich Text Format)?

If the file is produced by a program, post the code so that we can have a look.

If the file is created by a text editor etc, then the extension might affect how the data is stored (what are the line terminating chars etc) - which could effect how it's read/displayed by the program.

PS For info, L31-32 can be replaced with:

 
course.prerequisites.assign(substrings.begin() + 2, substrings.end());

Last edited on
My professor provided us with the data, but I had to save it myself onto a file in order to test the program. He plans on running multiple different size files through the program.

The first time I did it I believe I created a new file in the project and just copied and pasted the data there, which created a .txt file. For the .rtf one, I copied and pasted it into my text editor and then imported the file. The .rtf file prints good except for a slash at the end of the prerequisites.

I redid everything again, making a new file in the project and saving the data as a .txt file and it works totally fine. I guess when I did this the first time it must have saved weird, causing the issues. Still getting the hang of using files (clearly lol). Hopefully it'll be fine on my professor computer.

Does the replacement for L31-32 do anything different? Or is it just a better way to do it?
Last edited on
The replacement is just a shorter way of doing the same thing.

See http://www.cplusplus.com/reference/vector/vector/assign/

I don't know if you're covered iterators yet - but .begin() points to the beginning of the data and .end() points 1 past the end. So .begin() + 2 starts at the 2nd position. So the .assign() will copy the contents from the 2nd to the last position eg the prerequisites without requiring a loop.
My textbook pretty much grazed right over them, not explaining how to use them really so I wasn't feeling comfortable adding them.
Your explanation helps me understand them a lot more though, so thank you. I will definitely go ahead and replace that, as getting rid of the loop might help the speed a bit too.

Thank you again for all your help, I really appreciate it.
rtf is like html, it can have tags or other oddities in it, its not 'pure' text or not always pure.
all txt are rtf but not all rtf are txt
Last edited on
My textbook pretty much grazed right over them


Which book are you using?

See also https://www.learncpp.com/
Last edited on
Zybooks. I go to school online, so it's a weird one. Typically try to use this site or stackoverflow.com
Topic archived. No new replies allowed.