Reading and Decoding from Text File

Hello,
Below I have a set of code created to fulfill the following prompt. I have kind of squeezed together two sets of code that I started but am having trouble meshing-- if run how it is now, with the class and functions in comments, the program returns "Unable to open file."

PLEASE HELP ME!:)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You will read in an encoded message from a text file, then output the decoded message to another text file.

Here is the encoded message –

Mrkq#6=49#Dpsolilhg#Eleoh#+DPS,#%Iru#Jrg#vr#^juhdwo|`#oryhg#dqg#ghduo|#sul}hg#wkh#zruog/#wkdw#Kh#^hyhq`#jdyh#Klv#^Rqh#dqg`#^d`rqo|#ehjrwwhq#Vrq/#vr#wkdw#zkrhyhu#eholhyhv#dqg#wuxvwv#lq#Klp#^dv#Vdylru`#vkdoo#qrw#shulvk/#exw#kdyh#hwhuqdo#olih1
Copy this text and save it to a text file.

Write a C++ program that does the following:
Creates a class called Paragraph. It will have one private member variable of type string.
Opens the text file and reads in the text and stores it in an instance of “Paragraph”.
Decode the message by subtracting 3 from the ASCII value for each character (For example, ‘M’ becomes ‘J’, and ‘#’ becomes a space character).
Store the decoded message in another instance of “Paragraph”.
Output the decoded message to another text file.
If this is done successfully, you will see an English, decoded message in the new text file.

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

/* class Paragraph {
public:
	void SetText(char origTextUncoded);
private:
	char origText;
};

void Paragraph::SetText(char origTextUncoded) {
	origText = origTextUncoded;
} */

int main() {
	string line;
	string decode;
	string plaintext;
	ifstream myfile("decode.txt");
	
	if (!myfile.is_open()) {
		cout << "Could not open file decode.txt" << endl;
		return 1;
	}

	if (myfile.is_open())
	{
		while (getline(myfile, line))
		{
			decode = decode + line;
		}
		myfile.close();
		int i = 0;
		char ch;
		cout << "encrypted data :" << decode << '\n';
		while (i<decode.length())
		{
			ch = decode[i] - 3;

			plaintext = plaintext + ch;
			i++;
		}
		cout << "plaintext :" << plaintext << '\n';
		ofstream pfile("plaintext.txt");
		pfile << plaintext;

		pfile.close();
	}


	else cout << "Unable to open file";
	
	/* for (int i = 0; i < 188; i++) {
		inFS >> newText;
		newText = newText - 3;
	}
	inFS.close();

	cout << "Original text in decodeme.txt is: " << endl << "Mrkq#6=49#Dpsolilhg#Eleoh#+DPS,#%Iru#Jrg#vr#^juhdwo|`#oryhg#dqg#ghduo|#sul}hg#wkh#zruog/#wkdw#Kh#^hyhq`#jdyh#Klv#^Rqh#dqg`#^d`rqo|#ehjrwwhq#Vrq/#vr#wkdw#zkrhyhu#eholhyhv#dqg#wuxvwv#lq#Klp#^dv#Vdylru`#vkdoo#qrw#shulvk/#exw#kdyh#hwhuqdo#olih1" << endl;
	cout << "Using the ASCII value conversions, the decoded message is:" << endl;
	*/

	system("pause");
	return 0;
}
Hello juliabrushett,

Some things you can check on for now.

If the program cannot open the file first check that the file name in the program and the actual file match.

The other possibility is that you saved the file in the wrong sub directory and the program can not find it. Generally you would save the text file to the same sub directory as the ".cpp" files that the IDE is using. Another choice is to use the full path to the file.

Beyond that I will have to check out the program in the morning. For now the code looks like it should work, but I will know better later.

Hope that helps,

Andy
Hello juliabrushett,

I dug into the program this morning. Before I started fixing it the program worked fine, but did not match the instructions.

I find it helps to break up the instructions so that you know what you have to work with. Some times I put line numbers to help.

Write a C++ program that does the following:

1. Creates a class called Paragraph. It will have one private member variable of type string.

2. Opens the text file and reads in the text and stores it in an instance of “Paragraph”.

3. Decode the message by subtracting 3 from the ASCII value for each character (For example, ‘M’ becomes ‘J’,
and ‘#’ becomes a space character).

4. Store the decoded message in another instance of “Paragraph”.

5. Output the decoded message to another text file.

If this is done successfully, you will see an English, decoded message in the new text file.


I set up the class this way:
1
2
3
4
5
6
7
8
9
10
11
class Paragraph
 {
	public:
		Paragraph();  // <--- Default ctor.
		~Paragraph();  // <--- Default dtor.
		void SetText(std::string origTextUncoded);
		std::string GetText();

	private:
		std::string origText;  // <--- Changed to match directions.
};

The default ctor and dtor are not needed, but I thing it is good form to include them in the class.

Putting the member functions after the class is OK, but I like to put them after main. Eventually you will learn to put the class in its own header file and the member functions in its own ".cpp" file. This makes things less confusing when they are separate.

Your while loop to read the file is not really needed unless you have more than one line to read. Should you find that the input file has more than one line the private variable of the class will need to be changed to something that will hold more than one string. I would use a vector of strings for this. Of course this is just future thought.

This is what I did with the first while loop:
1
2
3
4
5
while (getline(myfile, line))
{
	decode = line;  // <--- Changed. Nor really needed.
	coded.SetText(decode);
}


Actually the while loop can be shortened to just:
1
2
while (getline(myfile, decode))
	coded.SetText(decode);


After this where you have used variables that are defined in main will have to be changed to use the member functions of the classes and the private variable of the classes.

At the end of the program you use "system".

It is best not to use "system" anything in a program as this could leave the program vulnerable to attack by hackers who can use this. Also it tends to be specific to Windows and not everyone can use it. If it is your own program and only you will be using it that is OK, but do not let it out to everyone. An alternative you can use is:
1
2
3
4
5
//  This next line may not be needed. If you have to press enter twice put a comment on the line.
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
//  Sometimes it is needed.
std::cout << "\n\n Press Enter to continue";
std::cin.get();


While I am here I off these pieces of knowledge for you enjoyment:

Try to avoid using using namespace std; in your programs it may seem easy now, but WILL get you in trouble some day.

It is better to learn to qualify what is in the standard name space with "std::" and then to learn what is in the standard name space now while it is easy. And not all at once to try to keep a job.

What you are most likely to use for now is "std::cout", "std::cin" and "std::endl". About a week or so of typing this and you will not even notice that you are doing it.

It is ALWAYS a good practice and programming to initialize your variables. If your compiler is using the C++11 standards or after the easiest way to initialize variables is with empty {}s, e.g., int num{};. This will initialize the variable to 0 (zero) or 0.0 for a double. A "char" will be initialized to "\0". "std::string"s are empty to start with and do not need to be initialized. Should you need to you can put a number between the {}s.You can also Initialize an array, e.g., int aNumbers[10]{};. This will initialize all elements of the array to 0 (zero). A use of
int aNumbers[10]{ 1 }; will initial the first element to "1" and the rest of the array to "0".. Following the "1" with ", 2 ..." will initialize the array with the numbers that you have used up to the entire array.

Any questions let me know.

Hope this helps,

Andy
Thank you SO much for your meticulous help! I really appreciate all of the explanations, as well.

Here is the code I have now:
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
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class Paragraph {
public:
	Paragraph();
	string GetText();
	void SetText(string origTextUncoded);
private:
	string origText;
};

void Paragraph::SetText(string origTextUncoded) {
	origText = origTextUncoded;
}

int main() {
	string text;
	string decoded;
	string coded;
	string plainText;
	ifstream inFS("decodeme.txt");
	
	if (!inFS.is_open()) {
		cout << "Could not open file decodeme.txt" << endl;
		return 1;
	}

	if (inFS.is_open()) {

		while (getline(inFS, text)) {
			decoded = text;
			coded.SetText(decoded);
		}
		inFS.close();
		
		int i = 0;
		char ch;
		int decodedLength = decoded.length();

		cout << "Using the ASCII value conversions, the decoded message is:" << endl << decoded << endl;
		
		while (i < decodedLength) {
			ch = decoded[i] - 3;

			plainText = plainText + ch;
			i++;
		}

		cout << "The original text in decodeme.txt is:" << endl << plainText << endl;
		ofstream pfile("plainText.txt");
		pfile << plainText;

		pfile.close();
	}

	else cout << "Unable to open file.";

	system("pause");
	return 0;
}


I was able to fix additional errors myself, but I still have a few more I can't seem to remedy.
Do I need to make "coded" a private class member? Also, while I don't think this should actually be a problem, I was thinking maybe the issue with line 44 had to do with the fact that an int and string were being compared (even though the length conversion is attached...) and so I went ahead and made a separate variable for decoded.length (appropriately called "decodedLength")... it didn't work:/ The only issues I am having now are as follows:

LINE35
class "std::basic_string<char,std::char_traits<char>,std::allocator<char>>" has no member "SetText"

LINE35
'SetText': is not a member of 'std::basic_string<char,std::char_traits<char>,std::allocator<char> >'

LINE44
'<':signed/unsigned mismatch
Hello juliabrushett,

The problem is not with line 35, but started back at lines 21 and 22. You defined these two variables as a "std::string" when they need to be defined with type "Paragraph". As the error message says "SetText" is not a member function of the "std::string" class. See http://www.cplusplus.com/reference/string/string/ to see what member functions are available.

Technically speaking line 44 in the above is a blank line. I am not sure if the warning message is referring to the next line or maybe line 41. I would think it started at line 41 because you define "i" as an "int", but the actual function call is defined as "size_t length() const;". You do not have to worry about the "const" part only the "size_t" part. "size_t" is just another name for "unsigned int" and one I use quite often as there are many functions that return a "size_t". Line 41 is not really necessary, you can use "decoded.length()" in the while loop, as you did in your original code, all you need to do is define "i" as "size_t i;" so that the variable and the return value match.

Lines 21 and 22 are the most important thing that needs fixed. The other is just a warning message and should not keep the program from compiling.

Hope that helps,

Andy
Hello juliabrushett,

After trying to compile the code I found that lines 21 and 22 need to be a "std::string",but what you are missing is:
1
2
Paragraph code;
Paragraph deCode;

You can change the variable name to whatever yo like.

Once I added these two lines and adjusted the lines that call member functions along with adding this: Paragraph::Paragraph() {}. Since you made a forward declaration in the class you need to define the function after the class as you did with "SetText()".

Then the program ran and produced the proper output. It also created the proper output file although it is one very long line like the input file.

Hope that helps,

Andy
Hi Andy!

First of all, thank you SO much for your continued help with this! I am just having such a hard time grasping the concept of classes, and your explanations are really wonderful. I have my program running, but my output is not coming out as desired. I've been playing around with the code but can't seem to figure out what the issue is. Here is what I have now:

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
66
67
68
69
70
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class Paragraph {
public:
	Paragraph();
	string GetText();
	void SetText(string origTextUncoded);
private:
	string origText;
};

Paragraph::Paragraph() {
}

void Paragraph::SetText(string origTextUncoded) {
	origText = origTextUncoded;
}

int main() {
	string text;
	string decoded;
	string coded;
	Paragraph code;
	Paragraph decode;
	string plainText;
	ifstream inFS("decodeme.txt");

	inFS.open("decodeme.txt");
	if (!inFS.is_open()) {
		cout << "Could not open file decodeme.txt" << endl;
		return 1;
	}

	if (inFS.is_open()) {

		while (getline(inFS, text)) {
			decoded = text;
			code.SetText(decoded);
		}
		inFS.close();
		
		int i = 0;
		char ch;
		int decodedLength = decoded.length();

		cout << "The original text in decodeme.txt is:" << endl << plainText << endl;
		ofstream pfile("plainText.txt");
		pfile << plainText;

		cout << "Using the ASCII value conversions, the decoded message is:" << endl << decoded << endl;
		
		while (i < decodedLength) {
			ch = decoded[i] - 3;

			plainText = plainText + ch;
			i++;
		}


		pfile.close();
	}

	else cout << "Unable to open file.";

	system("pause");
	return 0;
}


I must not be calling my files correctly, because my output is simply:
"The original text in decodeme.txt is:

Using the ASCII value conversions, the decoded message is:

"

Do I need to pass my string by reference maybe?
Hello juliabrushett,

As a start line 49 is wanting to print the variable "plainTest", but where above has "plainText" received a value? It does happen later in the program. You went to all the trouble to make a class and even stored the coded message in the class object "code". This is where you need to use the "GetText" function that you have not finished. Also line 49 should go after the following while loop when you actually have something to print.

That thought out of the way.

Line 45. Change "int" to "std::size_t" or leave the "std::" off if you want. "size_t" is another name for "unsigned int".

Line 47. You do not need this.

Line 55. In the while condition use while (i < decoded.length()). The ".lenghth()" and ".size()" function return a "size_t" so now 'i' matches the return value and everything will work. Now all you need to do is after the loop is store "plainText" in the other object of "Paragraph" "decode". Then in line 49 that moved to after the while loop use "decode.GetText()" in the cout statement.

If you understand all that the program will work.

Hope that helps,

Andy
Topic archived. No new replies allowed.