Search for string in file and get following string

Hey all.

I was wondering how I can search for a string in a text file and get it and the following word after it.

Here's an example of the text file:

HighScore.txt
----------------------------
Devin 101
Brian 428
Steve 145


Here's the code I have so far:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
playerName = userName;
bool userExists = false;
FileController fc;
string tmp;
while (!fc.getInFile().eof()) {
	fc.getInFile() >> tmp;
	if (tmp == userName) {
		cout << "Welcome back, "<< userName << "!\n\n" << endl;
		userExists = true;
		fc.getInFile().close();
		break;
	}
}
if (userExists == false) {
	cout << "Great! Let's begin!\n\n" << endl;
}


Essentially, I want the code to look in the file and try to find a matching user name and output a welcome message accordingly. Right now it gets hung up on the first word (this case being "Devin") and gets stuck in an infinite loop if you enter anything other than "Devin"

Any ideas?
Last edited on
I would be tempted to put the read in the wile test condition, so that the if statement is only performed on a valid read.

Also I would not close the file until the loop exits. You could be messing up the exit test by doing that.

1
2
3
4
5
6
7
8
9
10
while (fc.getInFile() >> tmp) {

	if (tmp == userName) {
		cout << "Welcome back, "<< userName << "!\n\n" << endl;
		userExists = true;
		break;
	}
}
fc.getInFile().close();
It's still not working for some reason. It just keeps hitting "Devin" infinitely if the name you provide doesn't match it.

Maybe it's in my file controller class?:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const string MY_FILE_NAME_ = "HighScores.txt";

FileController::FileController() {

}

// get data out.
ifstream FileController::getInFile() {
	string line;
	ifstream myFile(MY_FILE_NAME_);
	if (myFile.is_open()) {
		return myFile;
	} else {
		cout << "Error getting the file." << endl;
		exit(1);
	}
}


Here's my updated loop code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
playerName = userName;
bool userExists = false;
FileController fc;
string tmp;
				
while(fc.getInFile() >> tmp) {
	if (tmp == userName) {
		cout << "Welcome back, "<< userName << "!\n\n" << endl;
		userExists = true;
	}
}
fc.getInFile().close();
if (userExists == false) {
	cout << "Great! Let's begin!\n\n" << endl;
}


On ho, your opening a new file every time around the loop!!

When you open a new file it starts at the beginning again, no wonder it loops forever. In fact I am surprise you can compile this because you are returning an ifstream by copy, and I thought you couldn't copy streams....

You should only create one ifstream object for your file. fc.getInFile() should simply return a reference to that one copy.So something about the design of your class is not right.

Try making ifstream myFile a member of your class FileController and your call to getInFile() could then simply make sure the file is open. It should return a reference like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
class FileController
{
    std::ifstream myFile; // private member
public:
    public std::ifstream& getInFile() // return by reference &
    {
        if(!myFile.is_open())
        {
            myFile.open(MY_FILE_NAME_);
        }
        return myFile;
    }
};
Thanks for all your help so far Galik! I sincerely appreciate it!

I'm getting an error with those changes:

error C2065: 'myFile' : undeclared identifier
... error C2228: left of '.is_open' must have class/struct/union


with this code:
1
2
3
4
5
6
7
8
9
10
11
12
class FileController {
	ifstream myfile;
public:
	FileController();

	ifstream& getInFile() {
		if(!myFile.is_open()) {
            myFile.open("HighScores.txt");
        }
        return myFile;

	}


is the body of the getInFile() function supposed to be in the .cpp file? I couldn't get it to work there either
Last edited on
I don't see how the original could compile. I thought that streams were not copyable in C++. I would recommend posting the code that you are attempting to compile so that we can try it and see exactly what you are compiling and running. I'm not sure what the use of the FileController is. Using a wrapper class for the filestream object doesn't make sense to me.
I suppose I could get rid of the FileController class completely. It was originally a project requirement to have at least 5 classes. Now I have 7 so I could probably remove it.
@SacredFootballLB

In my code I misspelled myFile (capital F). Just make sure its spelled the same everywhere you use it (including case).
@Galik

I noticed the spelling error a few minutes after I posted my error. I was just focusing on the "must have a class/struct/union" part and not looking at the real problem ;)

One question I have: Why do you have 2 'public' declarations in the class file?
1
2
public:
    public std::ifstream& getInFile()...

I thought the first 'public' would make everything after it public.

I'm getting this error now (even if I implement the second public):
error C2248: 'std::basic_ios<_Elem,_Traits>::basic_ios' : cannot access private member declared in class 'std::basic_ios<_Elem,_Traits>'
My goodness what was I thinking? This public std::ifstream& getInFile(); should not have the public keyword. Must be a Java throwback....
How big is the file? Does it make sense to just read the file at startup and build a name/score map? In the current design it appears that you will have to do the file i/o many times as you search for each user. I am not sure what the requirements are but it seems to me that you could read each line into a string using getline and std::string. Then you could break the string up and create a std::map<std::string, int> so that you have each players info stored. Then as the program continues to run you can simply search the map for the player name anytime you want to get information for a player. That is just one idea but I don't know enough about your requirements and your initial post only contained a small snip from the program so I really don't have a good sense of what you are trying to make the program do.
I get those throwbacks from JAVA too, Galik ;)

@kempofighter
I'll try to clear some of it up. The program is a guessing game that will store users names and their scores so the file can be infinitely long, depending on how many people play it (for now, it is very short).

This loop is trying to check if a user has previously played (ie there is a username existing in the file that the user is using). If it does, it displays a welcome back message. If not, it'll begin with a different message and once the game ends, the user and their score will append to the end of the file.

I have another loop that runs through the program line-by-line that prints out the user and their scores. This is a "viewHighScores()" function. The loop I'm working on now is seperate from the viewHighScores() function.

Here's an example of how this loop should work:

Username = "Devin";
run through file
"Devin" exists in file
"Welcome back, Devin!"
...

Username = "Joe"
run through the file
"Joe" does not exist in file
"Let's play, Joe!"
...

make sense?
Last edited on
To make your list simple, you should iterate over all lines in the file and on each line split it. Once you done this you can store the results in a std::map<> for querying later.

Have a look at std::getLine() to retrieve an entire line from a file at a time.
Have a look at std::map to store the results.

I guess you could use strtok() to split; but you'd probably wanna write something a bit more robust that does it manually and puts some checks to ensure the format is correct.
@Zaita

Do I really need to store it? It's seems too simple of a check to see if the username string provided matches anywhere in the file to store it. I didn't think it'd make much sense trying to store the data in the program unless I'm overlooking something/not understanding.
Last edited on
I think I got it!

The error I was getting was from another file that was using the loop as well.

Here's the code in case someone has a similar problem ;)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
playerName = userName;
bool userExists = false;
FileController fc;
string tmp;
while(!fc.getInFile().eof()) {
	fc.getInFile() >> tmp;
	if (tmp == userName) {
		cout << "Welcome back, "<< userName << "!\n\n" << endl;
		userExists = true;
	}
}
fc.getInFile().close();
if (userExists == false) {
	cout << "Great! Let's begin!\n\n" << endl;
}


1
2
3
4
5
6
7
8
// FileController.h
class FileController {
	ifstream myFile;
public:
	FileController();

	ifstream& getInFile();
};


1
2
3
4
5
6
7
// implementation of getInFile() in FileController.cpp
ifstream &FileController::getInFile() {
	if(!myFile.is_open()) {
		myFile.open(MY_FILE_NAME_);
	}
        return myFile;
}


thank you so much everyone for your help and advice! :D
Last edited on
Topic archived. No new replies allowed.