String streams!

I have a simple encryption program here. I have to alter it so I can format the the name lines so that "King Beast Kong" would come out "Kong, King B." and "Fay Wray" would come out "Wray, Fay." I'm supposed to use string streams to divide the names into fields and I can't figure out how. This is the hint I'm given:

Place the name line into a stringstream object and then use the stringstream object’s input operator (>>) to read names into three string variables. If there are only two names, a first name and a last name, then the >> operator will read strings into the first two variables only, and the third variable will be left uninitialized. You can check to see whether or not only two names were read by checking the stringstream object’s fail function. If it is true, then you only read two names (it failed trying to read the third name).


Here is the sample file it's reading:
King Beast Kong
3:16 PM
Where are you?
Fay Wray
10:06 AM
At the south tip of the island
Ginger Rogers
12:06 PM
I should be at the south tip of the island in 15 minutes
King Beast Kong
12:15 AM
I've been waiting for hours. Where are you?


And here's my code so far:

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
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

string encryptor(string message, int key);

int main()
{
	int i=0, key;
	char filename[20];
	string line, name, time, message;
	ifstream blog;
	
	cout << "Enter the name of a blog file: ";
	cin >> filename;
	cout << "Enter an encryption key between 1 and 100: ";
	cin >> key;
	blog.open(filename);
	
	for(i=0;!blog.eof();i++){ //reads lines into variables
		getline(blog, line);
		name+=line;
		getline(blog, line);
		time+=line;
		getline(blog, line);
		message+=line;
		}
		cout << encryptor(message, key);
	return 0;
}

string encryptor(string message, int key){ //encrypts the message
	int j;
	char originalChar, encryptedChar;
	string encryptedMessage;
	for(j=0;j<message.length();j++){
		originalChar=message.at(j);
		if(originalChar+key>126){
			encryptedChar=32+((originalChar+key)-127);
		}
		else{
			encryptedChar=originalChar+key;
		}
		encryptedMessage+=encryptedChar;
	}
	return encryptedMessage;
}


I'm stuck but if you could help me out I'd really appreciate it!
A fun challenge for people of all ages!
What's the problem? The hint already tells you exactly how to do it.
Well I don't seem to be getting it right. All I can get is the King Beast Kong and none of the other names. I don't know if I should make name an array or make the first, middle, and last name variables arrays. How would you do it?
There are no arrays involved. Make sure the two or three parts end up correctly in three strings first, middle and last, then put them back together.
I'm just new to these string streams. Would I put the code in the initial for loop?
Look I like to figure these things out on my own but I've spent hours just on this one part and its probably something simple. If someone could just show me the code they would use on this one part I can assure you I'll have plenty more challenges to figure out on my own, all due by midnight.
Maybe I'm missing something, but the code you gave us doesn't even show your attempt at a solution to the problem, which is to organize the names in last name, first name (middle initial) format.
No you're right, I've tried a ton of combinations and nothing has worked. I was hoping someone that knew what they were doing could show me just how to properly feed the names into the string stream and into separate fields. I can figure out how to format it if I know that much.
Okay, I'll help a little.

Let's say you have the following line in a file called sample.txt:

one two three


And the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <fstream>
#include <sstream>

using namespace std;

int main()
{
    ifstream blog;
    stringstream ss;
    string line,first,second,third;
    blog.open("sample.txt");
    getline(blog,line);
    ss<<line; //Now the stringstream contains "one two three"
    ss>>first>>second>>third; //first contains "one", second contains "two", and third contains "three".
}


You'll need more to do the assignment but I don't want to give it all away. You'll need to clear the stringstream of the end of file error after it reads each line.
Last edited on
Thanks, I appreciate the help! But say the file contained:


one two three
one1 two1 three1


and I have to put one and one1 in the same category. This is really where my problem is because I can only get "King Beast Kong" to feed in and I'm not sure how to get it to move on and put the next name in.
You just make a function that takes the entire name and returns the fixed version.
Then you can continue reading other lines.
Umm, not sure exactly what you mean, but it sounds to me like you need to clear the stringstream. So, for instance, after reading in the first line and assigning "one" and "two" and "three" to strings 'first' and 'second' and 'third', clear the stringstream ss.clear(); since it's reached the end of file. Then use another getline for line 2, read line 2 into the stringstream, and then assign "one1" and "two1" and "three1" to strings 'first' and 'second' and 'third'. Like so:

1
2
3
4
5
6
7
getline(blog,line);
ss<<line; //line="one two three"
ss>>first>>second>>third; //first="one" second="two" third="three"
ss.clear();
getline(blog,line); //line="one1 two1 three1"
ss<<line;
ss>>first>>second>>third; //first="one1" second="two1" third="three1" 


Since you do not know whether a line has two or three words, you will need to use ss.eof() to check.

EDIT: Athar is right. A function would be better since you wouldn't need to clear the stringstream every time. Just be sure to declare the stringstream within the function, not within main.
Last edited on
Well I haven't learned the clear function yet but I'll take it. My brain is fried but here's what I have right now; not working right obviously.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
	for(i=0;!blog.eof();i++){

		getline(blog, line);
		name+=line;
		ss.str(name);
		ss >> name1 >> name2 >> name3;
		cout << name1 << name2 << name3;
		ss.clear();

		getline(blog, line);
		time+=line;
		getline(blog, line);
		message+=line;
		}
Well, first of all, use a function line Athar suggested. Then you won't need the clear function. Just forget I mentioned it (Although you should look into it on your own time if you're interested). What you really need is the fail function, as the hint suggested. Also, why do you keep appending each line onto name?

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

using namespace std;

int main()
{
string fixedName;
getline(blog,name)
fixedName=fixName(name);
}

string fixName(string a)
{
    stringstream ss;
    string first,second,third,fixed;
    ss<<a;
    ss>>first>>second>>third;
    if(ss.fail())
    {
    //This is the case where the line only had two words and so the stringstream failed in reading a third word.
    }
    else
    {
    //If the stringstream did not fail to read the third word.
    }
    return fixed;
}
Last edited on
Ok, that makes way more sense. Sometimes I get where I just can't think for myself anymore. I should be able to get it from here though, thanks for the help.
No problem.
Topic archived. No new replies allowed.