Write a C++ program that reads input from a text file and counts the number of characters read from the input. If the character read is a letter ('a'-'z'), counts the number of times that letter occurs [using an array] (both uppercase and lowercase should be counted as the same letter) in the input. Output the percentage of each letter in the input text, as well as the percentage of non-letter characters in the input.
Yes, this is a homework question, and I have most of it, but for some reason it isn't adding like I'd hoped.
#include <iostream>
#include <fstream>
#include <string>
#include <cctype>
using namespace std;
int main()
{
// make array with size of 26
// make array with all letter of alphabet
const int size = 26;
int narray[size];
char larray[26] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z' };
// all variables
int count = 0;
char character;
int length = 0;
int amount = 0;
int sum = 0;
double percent = 0;
// open file user inputs
ifstream input;
string file;
cout << "Please enter the file to be read" << endl;
cin >> file;
input.open(file);
if (input.fail())
{
cout << "Can't open file successfully." << endl;
return 1;
}
// count amount of characters and spaces in while loop
while (!input.eof()) //loop until the file ends
{
getline(input, file); // read every character
int c = file.length(); // count length
length += c;
}
// make every variable in array equal to 0
for (count = 0; count < size; count++)
{
narray[count] = amount;
}
// make for loop to read every character
for (int i = 0; i < length; i++)
{
input.get(character); // read characters
if (character <= 'A' && character >= 'z')
{
narray[tolower(character)-'a']++; // find out which variable of the array it is and add 1 to the amount
sum++;
}
}
// make for loop to print out array percentages
for (int j = 0; j < size; j++)
{
percent = (narray[j] / length) * 100;
cout << larray[j] << " " << percent << "%" << endl;
}
int non = (((length - sum) / length) * 100);
cout << "Non letter characters " << non << "%" << endl;
input.close();
return 0;
}
Your code is a little more complicated than it needs to be, but worse it has several bugs in it.
You are using 2 separate loops to do the job that 1 loop can do.
You are calling input.eof() before you have performed a read operation. The stream's state is not updated until after a read is attempted, so calling eof() before the 1st read is undefined behavior.
After you have read through the stream one time to EOF just to count its characters, you are not seeking the stream back to the beginning so you can then read the characters all over again.
You are not counting line break characters in the 1st loop, but you are reading line break characters in the 2nd loop, so the 2nd loop (potentially) won't read as many characters as the 1st loop had counted.
You are not testing for Uppercase and Lowercase letters correctly, and you are not accounting for the fact that in ASCII, there are 6 non-letter characters between the set of Uppercase letters and set of Lowercase letters. Your indexing of the narray[] array is all wrong while you are counting characters.
You are not accounting for the possibility that the file might be completely empty, or have ONLY linebreak characters in it and no non-linebreak characters. If either of those condition happens, your length variable will be 0, and you would get errors when you calculate percentages when dividing by 0.
With that said, try something more like this instead:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
// make array with size of 26
const int size = 26;
int narray[size] = {}; // make every variable in array equal to 0
// all variables
char character;
int count = 0;
int sum_letters = 0;
int sum_non = 0;
double percent;
string file, line;
// prompt user for filename
cout << "Please enter the file to be read" << endl;
getline(cin, file);
// open file
ifstream input(file);
if (!input.is_open())
{
cout << "Can't open file." << endl;
return 1;
}
//loop until the file ends
while (getline(input, line))
{
count += line.size(); // count every character
for (int j = 0; j < line.size(); ++j)
{
character = line[j];
// find out which variable of the array it is and add 1 to the amount
if (character >= 'A' && character <= 'Z')
{
narray[character-'A']++;
++sum_letters;
}
else if (character >= 'a' && character <= 'z')
{
narray[character-'a']++;
++sum_letters;
}
else
++sum_non;
}
}
input.close();
if (count != 0)
{
// make for loop to print out array percentages
for (int j = 0; j < size; ++j)
{
percent = (double(narray[j]) / count) * 100.0;
cout << ('a'+j) << " " << percent << "%" << endl;
}
percent = (double(sum_non) / count) * 100.0;
cout << "Non letter characters " << percent << "%" << endl;
}
else
{
cout << "File has no characters" << endl;
}
return 0;
}
If you want to include line breaks in the percentage of non-letter characters, then use this instead:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
// make array with size of 26
const int size = 26;
int narray[size] = {}; // make every variable in array equal to 0
// all variables
char character;
int count = 0;
int sum_letters = 0;
int sum_non = 0;
double percent;
string file, line;
// prompt user for filename
cout << "Please enter the file to be read" << endl;
getline(cin, file);
// open file
ifstream input(file);
if (!input.is_open())
{
cout << "Can't open file." << endl;
return 1;
}
//loop until the file ends
while (input.get(character))
{
++count; // count every character
// find out which variable of the array it is and add 1 to the amount
if (character >= 'A' && character <= 'Z')
{
narray[character-'A']++;
++sum_letters;
}
else if (character >= 'a' && character <= 'z')
{
narray[character-'a']++;
++sum_letters;
}
else
++sum_non;
}
input.close();
if (count != 0)
{
// make for loop to print out array percentages
for (int j = 0; j < size; ++j)
{
percent = (double(narray[j]) / count) * 100.0;
cout << ('a'+j) << " " << percent << "%" << endl;
}
percent = (double(sum_non) / count) * 100.0;
cout << "Non letter characters " << percent << "%" << endl;
}
else
{
cout << "File is empty" << endl;
}
return 0;
}
Related
We have to write this code for class, but I am getting an out-of-range error from the part of code below. It is supposed to be like a simon-says thing, where the letter you have to type in is the same. The exact error I'm getting is:
terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::at: __n (which is 1) >= this->size() (which is 1)
Abort (core dumped).
#include <iostream> // for I/O
#include <cstring> // for strlen()
#include <cstdlib> // for random numbers
#include <unistd.h> // for sleep()
using namespace std;
int main(int argc, char **argv) {
const int DEFAULT_NUMBER_OF_ROUNDS = 15;
int numRounds = DEFAULT_NUMBER_OF_ROUNDS;
// if a command line argument is given, use that string to init the
// "random" sequence and set the number of rounds to play the game
if (argc == 2) {
numRounds = strlen(argv[1]);
}
string s; // A string used to pause the game
char *seq = new char[numRounds]; // Sequence of numRounds colors to match
char colors[] = "RGBY"; // Allowable colors
bool lost = false; // Indicates whether we win or lose
int round; // Indicates the current round
// Initialize random number generator
srand(time(0));
// Determine the random color sequence using either argv[1] or
// randomly determined letters from 'R', 'G', 'B', and 'Y'
for (int j = 0; j < numRounds; j++) {
seq[j] = (argc == 2) ? argv[1][j] : colors[rand() % 4];
}
// Wait until the player is ready
cout << "Welcome to Simon, press enter to play .... ";
getline(cin, s, '\n');
//code
string input;
cout << flush;
int I;
round = 1;
while(!lost){
for(i = 0 ; i < round; i++){
cout << "Simon says: " << seq[i] << flush;
sleep(1);
cout << "\010." << flush << endl;
}
cout << "Please enter " << round << " characters to match ";
cin >> input;
if (numRounds <= round){
cout << "you won" << endl;
}
for(i = 0; i < round; i++);{
if(input.at(i) != seq[i]){
lost = true;
}
}
cout << "you lost" << endl;
cout << "the correct sequence was ";
for(int i = 0; i < round; i++){
cout << seq[I];
}
return 0;
}
}
The error message is telling you that you have a std::string whose size() is 1 character, and you are trying to use its at() method to access a character at an index which is >= 1, which is out of bounds.
One problem I see is that this loop:
for(i = 0; i < round; i++);{
^
Has an erroneous ; that causes the loop to do nothing but increment i until it reaches round, thus i is always equal to round in the subsequent expression if(input.at(i) != seq[i]). And at() performs bounds-checking, so will throw std::out_of_range if i >= input.size() is true.
After removing that erroneous semicolon, so the loop body is actually using i the way you intended, there is another problem. i is being used as an index into input and seq, however the lengths of input and seq are not guaranteed to be equal. Even though you are asking the user to enter round number of characters for input, you are not enforcing that.
The input.at(i) expression is the only expression in the whole program that is performing bounds-checking, and thus must be where the std::out_of_range error is being thrown from.
Also, you are never incrementing round. And, there is some logic in your while loop that should be moved after the loop has exited.
With that said, try something more like this:
#include <iostream> // for I/O
#include <cstring> // for strlen()
#include <cstdlib> // for random numbers
#include <limits> // for numeric_limits
#include <unistd.h> // for sleep()
using namespace std;
int main(int argc, char **argv) {
const int DEFAULT_NUMBER_OF_ROUNDS = 15;
int numRounds = DEFAULT_NUMBER_OF_ROUNDS;
// if a command line argument is given, use that string to init the
// "random" sequence and set the number of rounds to play the game
if (argc == 2) {
numRounds = strlen(argv[1]);
}
string seq(numRounds, '\0'); // Sequence of numRounds colors to match
char colors[] = "RGBY"; // Allowable colors
bool lost = false; // Indicates whether we win or lose
int round = 1; // Indicates the current round
// Initialize random number generator
srand(time(0));
// Determine the random color sequence using either argv[1] or
// randomly determined letters from 'R', 'G', 'B', and 'Y'
for (int j = 0; j < numRounds; ++j) {
seq[j] = (argc == 2) ? argv[1][j] : colors[rand() % 4];
}
// Wait until the player is ready
cout << "Welcome to Simon, press enter to play .... ";
cin.ignore(numeric_limits<streamsize>::max(), '\n');
//code
string input;
while (round <= numRounds){
for(int i = 0; i < round; ++i){
cout << "Simon says: " << seq[i] << flush;
sleep(1);
cout << "\b." << flush << endl;
}
do {
cout << "Please enter " << round << " character(s) to match: ";
cin >> input;
}
while (input.size() != round);
for(int i = 0; i < round; ++i){
if (input[i] != seq[i]){
lost = true;
break;
}
}
/* alternatively:
lost = (input.compare(0, round, seq, round) != 0);
*/
if (lost)
break;
++round;
}
if (lost){
cout << "you lost" << endl;
cout << "the correct sequence was ";
for(int i = 0; i < round; ++i){
cout << seq[i];
}
/* alternatively:
cout.write(seq, round);
*/
}
else {
cout << "you won" << endl;
}
return 0;
}
The user inputs some desired length of a string of characters . then the program outputs a list of randomly generated characters. After which the user is prompted to input 2 characters (that either exist or does not exist whiten the list). the program will then output where the first character appears in the pair or say that the pair does not exist in the list.
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
int main()
{
int size, c;
char ltr1, ltr2;
cout << "How many letters do you want in your random sting? ";
cin >> size;
string str;
for (int i = 0; i < size; i++)
{
c = rand() % 26 + 'a';
str.push_back(c);
}
for (int i = 0; i < size; i++)
{
cout << str[i];
}
cout << endl << endl;
cout << "what pair of letters would you like to find?";
cin >> ltr1;
cin >> ltr2;
cout << endl;
for (int i = 0; i < size; i++)
{
if (char((str[i] == ltr1) && (str[i + 1] == ltr2)))
{
cout << "the pair is in the string starting at character number "
<< i << " in the string" << endl;
}
if (char((str[i] == ltr1) && (str[i + 1] != ltr2)))
{
cout << "the pair " << ltr1 << ltr2 << " is not in the string." << endl;
}
}
return 0;
}
the output is capable of determining weather or not the pair exist or not and will output the location however if you input a value greater than 25 it will run the final output multiple times.
I have a text file containing sort of a graph presentation, as such:
7
{5, 2, 3}, {1,5}, { }, { }, {3}, { }, { }
Now, I know how to read a file and get in into an int
while ((n = myfile.get()) != EOF)
or into a string line by line
getline (myfile,line)
The problem I have, is that with both of these options I can't really seem to compare every character I extract and check if it's a number or a "," or "{" or "}".
Is there a simple way of doing that? I've been banging my head with this for hours since yesterday. I've tried some isdigit and casting, but that didn't work for me as well and really complicated stuff.
The easiest solution, I think, would be to get your hands dirty a bit, by reading the file char by char. I suggest you store the sets in a vector of vectors of ints (visualize it like a 2D array, a matrix, if you like).
If the i-th set is empty, then the i-th vector will be empty too.
In the loop in which you will parse the characters, you will skip the opening curly braces and commas. You will do similarly for the closing curly braces, except from the fact that you would need to update an index, which will help us update the index-th vector.
When we actually read a digit, then you can convert a char to an int.
Complete example:
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main(void) {
char ch;
fstream fin("test.txt", fstream::in);
if(!fin) {
cerr << "Something is wrong...! Exiting..." << endl;
return -1;
}
int N; // number of sets
fin >> N;
vector<vector<int> > v;
v.resize(N);
int i = 0;
while (fin >> ch) {
//cout << ch << endl;
if(ch == '{' || ch == ',')
continue;
if(ch == '}') {
i++;
continue;
}
v[i].push_back(ch - '0');
}
if(i == N) {
cout << "Parsing the file completed successfully." << endl;
} else {
cout << "Parsed only " << i << " sets, instead of " << N << endl;
}
for(size_t i = 0; i < v.size(); ++i) {
if(v[i].size() == 0)
cout << i + 1 << "-th set is empty\n";
else {
for(size_t j = 0; j < v[i].size(); ++j)
cout << v[i][j] << " ";
cout << endl;
}
}
return 0;
}
Output:
gsamaras#aristotelis:/Storage/homes/gsamaras$ g++ main.cpp
gsamaras#aristotelis:/Storage/homes/gsamaras$ ./a.out
Parsing the file completed successfully.
5 2 3
1 5
3-th set is empty
4-th set is empty
3
6-th set is empty
7-th set is empty
Important note: This should serve as a starting point, since it won't treat numbers that have more than one digits. In this case, you will to read up to the comma, or the closing curly brace, to make sure that you read all the digits of the numbers, then convert from string to integer, and then store it in the corresponding vector.
Its better to read character by character as follows:
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main()
{
string line;
int lineNum = 0;
ifstream myfile ("file.txt");
if (myfile.is_open())
{
while ( getline (myfile, line) )
{
// Identifying the type of charcter
char a;
cout << "Line Number " << ++lineNum << ": ";
for(int i = 0; i < line.length(); i++)
{
a = line[i];
cout << "\n\t" << a;
if((a >= 32 && a <= 47) || (a >= 58 && a <= 64) || (a >= 91 && a <= 96) || (a >= 123 && a <= 126))
{
cout << "\t(This character is either a Punctuation or arithmetic mark.)";
// If you don't want to porcess these character, then you may 'continue' to the next sub string
}
else if(a >= 48 && a <= 57)
{
cout << "\t(This character is a number.)";
// If you want to change the number ot int, you can use atoi or stoi
}
else if(a >= 65 && a <= 90)
cout << "\t(Capital letter)";
else if(a >= 97 && a <= 122)
cout << "\t(Small letter)";
}
cout<<endl;
}
myfile.close();
}
else
cout << "Unable to open file";
return 0;
}
I hop this helps.
I'm trying to figure out how exactly I'd use my output text file I created to be used to calculate the sums of both variables. My output text file is saving the information correctly, but I get 0 and 0 for my sums so it's not reading the information I think. Also, does the information I enter into the arrays only save into the text file? I need it only being saved into the text file so that the sum calculations are only receiving information from the text file
#include <iostream>
#include <string>
#include<iomanip>
#include <fstream>
using namespace std;
int main() {
int ItemNumber[2];
float price[2];
int sumnumber = 0;
float sumprice = 0;
string myfile = "c:/Users/rz/Desktop/numbers.txt";
int count = 0;
ofstream outFile;
outFile.open(myfile);
while (count <= 1)
{
cout << "enter a price" << endl;
cin >> price[count];
outFile << price[count] << endl;
cout << "enter a item number" << endl;
cin >> ItemNumber[count];
outFile << ItemNumber[count] << endl;
count++;
}
outFile.close();
fstream inFile;
inFile.open(myfile);
while (count <= 1)
{
sumprice = sumprice + price[count];
sumnumber = sumnumber + ItemNumber[count];
}
cout << sumnumber << endl;
cout << sumprice << endl;
system("pause");
return 0;
}
At the end of the first loop:
int count = 0;
while (count <= 1) { ... count++ ... }
the variable count will be set to 2.
Then, when you start the second loop:
while (count <= 1) ...
the condition is already false, hence the body of the loop will never be executed.
In order for this to work, you would have to reset count back to zero so that it runs through the items again. Or, better yet, leave count alone (since it indicates how many items were processed) and use another variable to got through them:
for (int i = 0; i < count; ++i) { ... use i rather than count ... }
I'm making a program that converts a string that the user enters such as "APPLE" into a binary number through the corresponding ASCII numbers that represent each character of the string "APPLE." For example A = 65 in ascii etc.. I've created a function that converts the string into a binary but it doesn't seem to be working. It displays "The equivalent binary number is: 0031F240for A" in an infinite loop and gives me "0031F240for" instead of being in the binary version of 65. I know this function works for converting a decimal number into binary because I've tried it, but I think my implementation of the bin[] array is messing things up. Any help would be appreciated.
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
#include <fstream>
using namespace std;
class RandomString
{
private:
string input;
string bin[100];
public:
RandomString() : bin(), input("")
{
}
void getData()
{
cout << "Enter the word to be encoded into a binary file.";
cin >> input;
}
void numToBin()
{
int i = 0;
int len = input.length();
int num = int(input[i]);
for(int i = 0; i < len; i++)
{
while(num != 0)
{
if (num % 2 == 0)
bin[i].insert(0, "0");
else
bin[i].insert(0, "1");
num = num / 2;
cout << "The equivalent binary number is: " << bin << "for " << input[i] << endl;
}
}
}
void display()
{
}
};
I haven't test if the result is correct but this code convert a string to binary. Probably you have to modify it to fit with ASCII codes.
void DecimalToBinary(char a,std::vector<char>& v)
{
if(a==0)
v.push_back(0);
if(a==1)
v.push_back(1);
else
{
v.push_back(a%2);
DecimalToBinary(a/2,v);
}
}
int main()
{
std::vector<char> v;
std::string line;
getline(std::cin,line);
std::istringstream input(line);
char c;
while(input >> c)
{
DecimalToBinary(c,v);
}
std::copy(v.begin(),v.end(),std::ostream_iterator<int>(std::cout,""));
}
First Your while loop never stops because you don't change the value of i inside the while loop, so int(input[i]) has always the same value, you have to use break somewhere or i++, but I don't know if the result is correct,I think recursion is better than while in this situation, but anyway try the following:
void numToBin()
{
int i = 0;
int len = input.length();
int num = int(input[i]);
for(int i = 0; i < len; i++)
{
while(int(input[i]) != 0)
{
if (num % 2 == 0)
{
bin[i].insert(0, "0");
break;
}
else
{
bin[i].insert(0, "1");
num = num / 2;
}
cout << "The equivalent binary number is: " << bin << "for " << input[i] << endl;
}
}
}
Second, doing std::cout << bin you print a memory address, not the contents of the bin.
while(int(input[i]) != 0)
{
if (num % 2 == 0)
bin[i].insert(0, "0");
else
{
bin[i].insert(0, "1");
}
num = num / 2;// this line should be in both case.
cout << "The equivalent binary number is: " << bin << "for " << input[i] << endl;
}
I've changed num = num / 2 for both cases. Please check it.
You may want to change the 'bin' in
cout << "The equivalent binary number is: " << bin
to 'bin[i]'.
Because 'bin' is a string array, also the pointer/address to the string array, so 'cout << bin' will always output the address.