Obtaining the right data from a .txt file

Pages: 12
Hello all,

I am trying to create a useful program for myself that can calculate the overall team score in a student organization I am in (there are many different competitive events, each event has a top ten award, then they give an overall award based on a school's results on all of the events), but I think its demands might be a little out of my knowledge base (I have only had one programming class).

I am trying to create a program does the following things:
*asks the user to input the name of a school
*reads through data in a .txt file and finds the school name
*after finding the school name, read what place the school finished in that particular event
*assigns a point value based on the school's place in the event, and keeps a running total of the point value
*after running through all the events and adding the point values, cout the total points earned by the school.

Here is an example of the .txt file, so you can see how it is formatted (there are spaces and extraneous information)

Inventions & Innovations (MS)
Place School Name State
1 Westside Middle School FL
2 Louise R Johnson FL
3 Lake Riviera Middle School NJ
4 R. Dan Nolan Middle School FL
5 Carver Middle School NC
6 Daniel Jenkins Academy FL
7 Bearden Middle School TN
8 Harmony Community School FL
9 Chattanooga Valley Middle GA
10 Carnegie Middle High School OK


Leadership Strategies (MS)
Place School Name State
1 R. Dan Nolan Middle School FL
2 Harmony Community School FL
3 The Stem School And Academy CO
4 E. H. Markle Intermediate School PA
5 Welsh Valley Middle School PA
6 Louise R Johnson FL
7 Signal Mountain Middle School TN
8 Holland Township School NJ
9 Robert Frost Middle School VA
10 Altoona Area Junior High School PA

*Note: when I preview this it is misleading - there is a tab between the place and the school name, and between the school name and the state. In preview it looks like only a space. But it is not just a space, they hit tab.

This is how the formatting is supplied as, so I cannot make changes to it. I know I will have to skip the event title and the other pre-lim info somehow, and then start reading the names of the schools, looking for the name that the user inputted.

I enjoy the puzzle of creating programs (I usually don't ask for help, just think about it over weeks), but I am having trouble with the "reading the data and finding the name of the school" part. The formatting of the txt file is making this tricky for me to think about - the school name is after the place finished but I need to find the school name first before getting the place finished. I think I may not have the knowledge of how to do this yet, but maybe I do. I am just stuck with how I will accomplish this. I know I can do the math part of it, but it's the reading the right info of the .txt file that is troubling me.

Thanks in advance for the help!

Chf. Os
Instead of reading the file after asking the user for a school, load the file into a list at the start of the program. Then you can just iterate through the list searching for the school name, and return its position once you find it.
I'm not sure what you mean...reading the file first and then asking for the school name still presents me with the same problems

EDIT:What do you mean by loading the file into a list?
Last edited on
At the start of the program, load the file into some sort of data structure. Then when the user gives you a school name, you can search the structure.

After some thinking though, while that method should be faster, it also could be more complicated.

After getting the school name cin >> schoolName;, read the file line by line getline ( file, tempString ); and search the tempString for the school name: tempString.find ( schoolName );.

If you find it (if ( tempString.find ( schoolName ); )), you can get its placement with int placement = stoi ( tempString.substr ( 0, tempString.find ( '\t' ) ) );.
Last edited on
Ok, but if I use getline, would that not also read the place finished, and state, so it would not match the name of the school that the user inputs?
That's why you use find and not ==.
ok, I think I understand what to do for finding the school name, but I am unfamiliar with what you did for the "getting the placement" part. Are you converting something to an int if the name is found?
Sorry, I did squish it all together a bit much.

tempString.find ( '\t' ) returns the location of the first tab character in the string. In this case it would be the one right after the placement number. For placements 1-9 this will equal 1, for placement 10 this will equal 2.

tempString.substr ( num1, num2 ) returns a substring of tempString starting at position num1 lasting for num2 characters. In this case it will start at position 0 and go for either 1 or 2 characters ( based on what tempString.find ( '\t' ) returns ).

atoi ( ) takes a string and returns an integer.


So if tempString equals "7 Bearden Middle School TN", placement would equal 7.
So this is the code in question:

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
inputFile.open("nationals.txt");		//Opens file

	//If not in file, display error message, and exit 
	if ( !inputFile )					
	{
		cout << "Error: Data file could not be opened - check file name" << endl;
		exit (EXIT_FAILURE);
	}


	// Ask user for school name
	cout << "Please enter a a school name:\n>";
	getline(cin, input);

	//Read the first line in the file
	getline(inputFile, tempString);

	//Search first line for school name
	tempString.find (input);

	//If school name is found, get the place they finished
	if( tempString.find (input) )
	{
		int placement = stoi ( tempString.substr ( 0, tempString.find ( '\t' ) ) );

	}


And then get the next line and so on?
Pretty close. You need to initialize placement outside of the loop or it will be destroyed upon exiting the loop. Also, line 19 doesn't do anything. I added in the loop so that it will check the entire file, as well as an empty if..else statement for you to use.

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
#include <iostream>
#include <string>
#include <fstream>

using namespace std;

int main ( )
{
	ifstream inputFile ( "nationals.txt" ); // Opens file

	string schoolName, temp;

	int placement = 0;



	// If input file could not be opened.
	if ( !inputFile )					
	{
		cout << "Error: Data file could not be opened.\n"
			"Check that the file name is 'nationals.txt'.\n";

		return 0;
	}


	// Ask and get a school name from the user.
	cout << "Please enter a a school name: ";
	getline ( cin, schoolName );


	while ( getline( inputFile, temp ) ) // Read the next line in the file.
	{
		if ( temp.find ( schoolName ) ) // Search line for the school name.
		{ // If school name is found, get its placement.
			placement = stoi ( temp.substr ( 0, temp.find ( '\t' ) ) );
		}
	}


	inputFile.close ( ); // Close the input file since it's not used after this point.


	if ( !placement ) // The school was not found in the file.
	{
		// Do Something
	}

	else
	{
		// Do Something Else
	}
}
Last edited on
So the above would get the school name from the user, get the first line, if the name is in the line get their place, otherwise go to the next line. Now what I really want to do is keep a running total of the overall points the school has (described in my initial post). So I need to convert the place into points, which I did, as seen below:

1
2
3
4
5
if ( temp.find ( schoolName ) ) // Search line for the school name.
		{ // If school name is found, get its placement.
			placement = stoi ( temp.substr ( 0, temp.find ( '\t' ) ) );
                        int points = PLACE_MATH - placement;
		}


Where the const int PLACE_MATH is 11 (11 minus your place gives you your points). So how do I keep a running total of these points, and then print them at the end?
Last edited on
I would create a vector of pairs of a string and an int std::vector<std::pair<std::string,int>>.

The string would hold the school name, and the int would hold its points.
I'm not sure I entirely understand what you are saying (I am unfamiliar with what you did above), but from what I think you are saying, I don't see the need, because I do not need to hold the name of multiple schools at a time - the user inputs the name, and then the score is the output. From what I thought, at this point I would just need to have some variable outside the while loop that would hold the points, and then at the end output them. Is this incorrect?
If you only need to keep the score for one school, then yes that would be enough.
Ok, so this is how the code looks now - note that I removed the initializer of the placement int outside because it does need to reset after each iteration, and instead have a points int that will hold the points throughout (I think this is right)

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
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cmath>
#include <string>

using namespace std;

const int PLACE_MATH = 11;


int main()
{
	ifstream inputFile;					//Declare input file stream
	string input = "";					//Declare school name
	string temp;					//Declare temporary string to be read
	int points = 0; 
 
	inputFile.open("nationals.txt");		//Opens file

	//If not in file, display error message, and exit 
	if ( !inputFile )					
	{
		cout << "Error: Data file could not be opened - check file name" << endl;
		exit (EXIT_FAILURE);
	}


	// Ask user for school name
	cout << "Please enter a a school name:\n>";
	getline(cin, input);

	while ( getline( inputFile, temp ) ) // Read the next line in the file.
	{
		if ( temp.find ( input ) ) // Search line for the school name.
		{ // If school name is found, get its placement.
			int placement = stoi ( temp.substr ( 0, temp.find ( '\t' ) ) );
			points = PLACE_MATH - placement;
		}
	}

	inputFile.close ( ); // Close the input file 

	cout << "Your total points: " << points << endl;

	
	
	return 0;

}
Line 38 should be points += PLACE_MATH - placement; or points will be set to only one of their placements instead of the sum. Other than that it looks like it should work.
Last edited on
Something is amiss...I made the change (thanks), and it builds without errors. But when I input a school name, I get "Debug Error! R6010 abort() has been called...not sure why
My guess is that temp.find ( '\t' ) isn't finding a tab character. Try temp.find_first_of ( " \t" ) instead. This will search for the first tab character or the first space character, whichever it finds first.
Same error, though after some testing it is definitely something in the int statement that is causing the issue
there may be something wrong with the finding code...I removed the math part of the if statement, and just have it so if it finds the input name, it will cout a message. No matter what I input, it finds it 7 times (same as number of lines in my txt file)
Pages: 12