Reading a file with c++ containing chars and numbers - c++

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.

Related

C++ Question: string.at function returns a "std::out_of_range" error in terminal

I've been working on this code for a while now and I keep getting the same terminal error. I have narrowed the issue down to two at functions. I've looked it up but the only answer I can seem to find is if the coder used the wrong variable in a for loop or that the variable in the at function isn't indexed properly.
Can't seem to figure out why the str.at() functions specifically are throwing errors when the variable str should be initialized. The at functions in question are the second and fourth if statements inside the do-while loop.
Here's the code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
// start main function
int main()
{
ifstream infile;
string line;
string str;
int words = 0;
int charsNotIncludingSpaces = 0;
int charsIncludingSpaces = 0;
int wordsEndingWithE = 0;
int sixLetterWords = 0;
int wordsBeginningWithVowel = 0;
int wordsContainingATE = 0;
int allEs = 0;
int wordsWithAtleastTwoEs = 0;
infile.open("USDictionary.txt");
// read the first line from the file
getline(infile, line);
while(!infile.eof())
{
unsigned int startIndex = 0;
unsigned int endIndex = 0;
// get each word from the line and find the required results
do
{
endIndex = line.find(' ', startIndex);
if(endIndex > 0 && endIndex < line.size())
{
str = line.substr(startIndex, endIndex - startIndex);
}
else
{
str = line.substr(startIndex);
}
startIndex = endIndex + 1;
words++;
charsNotIncludingSpaces += str.size();
if(str.at(str.size() - 1) == 'e')
{
wordsEndingWithE++;
}
if(str.size() == 6)
{
sixLetterWords++;
}
if(str.at(0) == 'a' || str.at(0) == 'A'
|| str.at(0) == 'e' || str.at(0) == 'E'
|| str.at(0) == 'i' || str.at(0) == 'I'
|| str.at(0) == 'o' || str.at(0) == 'O'
|| str.at(0) == 'u' || str.at(0) == 'U')
{
wordsBeginningWithVowel++;
}
unsigned int ateIndex = str.find("ate");
if (ateIndex >= 0 && ateIndex < str.size())
{
wordsContainingATE++;
}
for (unsigned int k = 0; k < str.size(); k++)
{
if(str.at(k) == 'e')
allEs++;
}
if (str.find_first_of('e') != str.find_last_of('e'))
{
wordsWithAtleastTwoEs++;
}
} while (endIndex > 0 && endIndex < line.size());
charsIncludingSpaces += line.size();
// read the next line from the file
getline(infile, line);
}
infile.close();
/*// print the results
cout << "Total number of words in the dictionary: "
<< words << endl;
cout << "Total number of characters in the dictionary (not including white spaces): "
<< charsNotIncludingSpaces << endl;
cout << "Total number of characters in the dictionary (including white spaces): "
<< charsIncludingSpaces << endl;
cout << "Total number of words ending in the letter e: "
<< wordsEndingWithE << endl;
cout << "Total number of 6 letter words: "
<< sixLetterWords << endl;
cout << "Total number of words beginning with a vowel: "
<< wordsBeginningWithVowel << endl;
cout << "Total number of words containing the substring \"ate\": "
<< wordsContainingATE << endl;
cout << "Total number of occurances of the letter e: "
<< allEs << endl;
cout << "Total number of words containing at least two occurances of the letter e: "
<< wordsWithAtleastTwoEs << endl;*/
return 0;
}

Question - c++ terminate called after throwing an instance of 'std::out_of_range' what(): basic_string::substr:?

I'm new to coding and trying to create a program to encrypt/decrypt based on a map of 26 characters. The encryption part of the code works, but whenever I try to decrypt, I get the error
terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::at: __n (which is 122) >= this->size() (which is 5).
What should I do?
#include <iostream>
#include <cstring>
using namespace std;
string encrypt(string word, string map = "zyxwvutsrqponmlkjihgfedcba") {
string output = "";
for(int i = 0; i < word.length(); i++) {
int pos = word.at(i) - 'a';
output += map.at(pos);
}
return output;
}
string decrypt(string word, string map = "zyxwvutsrqponmlkjihgfedcba") {
string output = "";
for(int i = 0; i < word.length(); i++) {
int pos = map.at(i);
output += word.at(pos) + 'a';
}
return output;
}
int main() {
string method, word, map;
cout << "What is the method (encryption or decryption)? ";
cin >> method;
if(method.compare("encryption") != 0 && method.compare("decryption") != 0) {
cout << "Error: invalid method choice.\n";
return 0;
}
cout << "What is the translation map (type 'default' to use default): ";
cin >> map;
if(map.compare("default") && method.length() != 26) {
cout << "Error: invalid translation map size.\n";
return 0;
}
cout << "What is the single word to translate: ";
cin >> word;
if(method.compare("encryption") == 0) {
for(int i = 0; i < word.length(); i++)
if(!isalpha(word.at(i)) || !islower(word.at(i))) {
cout << "Error: encryption cannot be performed.\n";
return 0;
}
if(map.compare("default") == 0)
cout << "Encrypted word: " << encrypt(word) << endl;
else
cout << "Encrypted word: " << encrypt(word, map) << endl;
}
if(method.compare("decryption") == 0) {
if(map.compare("default") == 0)
map = "zyxwvutsrqponmlkjihgfedcba";
for(int i = 0; i < word.length(); i++)
if(map.find(word.at(i)) == string::npos) {
cout << "Error: decryption cannot be performed." << endl;
return 0;
}
if(map.compare("default") == 0)
cout << "Decrypted word: " << decrypt(word) << endl;
else
cout << "Decrypted word: " << decrypt(word, map) << endl;
}
}
Looks like you're misunderstanding the meaning of string::at.
Consider the lines:
int pos = map.at(i);
output += word.at(pos) + 'a';
at simply gives you back the ASCII value of the character at position i in the string. Supposing i is zero, this is 'z' which has an ASCII value of 122.
You then try to look up the character at position 122 in word, word does not have that many characters. I'm not sure exactly what you're trying to do, but it's not that.

C++ Letter Occurrences

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;
}

Having trouble grasping simple boolean loop if/else program in C++

I need a little help figuring out a couple of parts from a C++ assignment. I am asked to write a program as follows:
Write a program that accepts input from the keyboard (with the input
terminated by pressing the Enter key) and counts the number of letters (A-Z and a-z), numerical digits (0-9), and other characters. Input the string using cin and use the following looping structure to examine each character in the string with an "if" statement and multiple "else if" statements.
char s[50];
int i;
. . .
i = 0;
while (s[i] != 0) { // a string is terminated with a null (0) value
. . .
i++;
}
Your program should make use of the relational operators (e.g., == < > <= >= !=) to determine whether a particular character is a letter, number, or other character. You may only #include and
may not use any other include files.
The program should have an output similar to the following:
Enter a continuous string of characters with no blank spaces (example: aBc1234!##$%)
enter your string: aBc1234!##$%
your string has 12 total characters
3 letters
4 numerical characters
5 other characters
Here is an example program that counts lower case letters:
// PROG07.CPP example
#include <iostream>
using namespace std;
int main()
{
char s[50];
int i;
int lowercase = 0;
//get string from the user
cout << "Enter a continuous string of characters with no blanspaces\n"
cout << "(example: aBc1234!##$%)" << endl << endl;
cout << "Enter your string: ";
cin >> s;
cout << endl;
// loop through the string, lower case letters
// note, strings (character arrays) have an invisible
// zero value at their end
i = 0;
while (s[i] != 0) // while the character does not have ASCII code zero
{
if ((s[i] >= 'a' && s[i] <= 'z'))
lowercase++;
i++;
}
cout << "Your string has " << lowercase << " lower case letters" << endl;
// including the next line for Dev-C++:
system("pause"); // not needed for CodeBlocks
return 0;
}
So far, I have come up with this:
#include <iostream>
using namespace std;
int main()
{
char s[50];
int i;
int lowercase, uppercase, numChars, otherChars = 0;
cout << "Enter a continuous string of characters" << endl;
cout << "(example: aBc1234!##$%)" << endl;
cout << "Enter your string: ";
cin >> s;
cout << endl;
while (s[i] != 0) // while the character does not have ASCII code zero
{
if ((s[i] >= 'a' && s[i] <= 'z'))
lowercase++;
i++;
}
while (s[i] != 0)
{
if ((s[i] >= 'A' && s[i] <= 'Z'))
uppercase++;
i++;
}
cout << lowercase + uppercase << " letters" << endl;
i = 0;
while (s[i] != 0)
{
if ((s[i] >= '0' && s[i] <= '9'))
numChars++;
i++;
}
cout << numChars << " numerical characters" << endl;
return 0;
}
Any help would be greatly appreciated.
You have to reset i to 0 before every loop:
#include <iostream>
using namespace std;
int main()
{
char s[50];
int i;
int lowercase, uppercase, numChars, otherChars = 0;
cout << "Enter a continuous string of characters" << endl;
cout << "(example: aBc1234!##$%)" << endl;
cout << "Enter your string: ";
cin >> s;
cout << endl;
i = 0; //missing
while (s[i] != 0) // while the character does not have ASCII code zero
{
if ((s[i] >= 'a' && s[i] <= 'z'))
lowercase++;
i++;
}
i = 0; // missing
while (s[i] != 0)
{
if ((s[i] >= 'A' && s[i] <= 'Z'))
uppercase++;
i++;
}
cout << lowercase + uppercase << " letters" << endl;
i = 0;
while (s[i] != 0)
{
if ((s[i] >= '0' && s[i] <= '9'))
numChars++;
i++;
}
cout << numChars << " numerical characters" << endl;
return 0;
}
Looks good so far, just a few things
First off, you only need the one while loop:
while (s[i] != 0)
{
//All your if checks can go in here
}
Then, according to the output you need, you will need 4 variables:
int total, lettters, numbers, otherCharacters;
At the start of your loop, add to total:
while (s[i] != 0)
{
total++;
}
Then you will need 3 if checks inside your while loop, one for letters, one for numbers, and one for other characters:
if ((s[i] > 'a' && s[i] < 'z') || (s[i] > 'A' && s[i] < 'Z')) { ... }
else if (s[i] > '0' && s[i] < '9') { ... }
else { ... }
Then just output all your variables according to the output you mentioned:
cout << "your string has " << total << " total characters, " << letters << " letters, " << numbers << " numerical characters, and " << otherCharacters << " characters.";

Strange first element of array after reading in from file

I'm reading in a sodoku board from a text file. The board is represented by 9 rows of 9 digit numbers, like this:
594632817
123478569
678159234
215346798
346897125
789215346
437561982
851924673
962783451
EDIT
Here are the results when I change the while condition to (input >> char):
Output as chars are read in:
96212486
71931369
48728254
35185947
67350
Output of printArray:
962124867
193136948
728254351
859476735
�$%w��
����QȿȔ
L�`g�Pw
���w�
And here's the output for while (!input.eof()):
�94632817
123478569
678159234
215346798
346897125
789215346
437561982
851924673
962783451
END EDIT
The trouble is, when I place each digit into a multidimensional array, the element at [0][0] appears as a shaded question mark (compiled with g++). The problem only surfaces when I'm printing out the contents of the array, the data as it's read in appears to be fine. For what it's work, this also happens if I cout << board[0][0] from the main function.
Any help would be appreciated!
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int createArray(string filename);
bool checkRows(char board[][9]);
bool checkColumns(char board[][9]);
bool checkBoxes(char board[][9]);
void printArray(char board[][9]);
int main ()
{
char board [9][9];
int i = 0;
int j = 0;
int count = 0;
ifstream input("board.txt");
char ch;
while (input >> ch)
{
// ch = input.get();
if (ch != '\n')
{
cout << ch;
board[i][j] = ch;
j++;
if (j % 9 == 0)
{
i++;
}
}
if (j > 8)
j = 0;
if (i > 8)
i = 0;
count++;
if (count % 10 == 0)
cout << endl;
}
input.close();
printArray(board);
cout << checkRows(board) << endl;
cout << checkColumns(board) << endl;
return 0;
}
void printArray(char board[][9])
{
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
cout << board[i][j];
}
cout << endl;
}
cout << board[0][0] << endl;
cout << board[0][1] << endl;
}
By doing this, reading ch two times.
Remove ch = input.get(); and you will read each number correctly.
while (input >> ch)
{
ch = input.get();
...
}
Again, consider changing condition below to make sure correct endl placement
if (count % 10 == 0)
cout << endl;
to
if (count % 9 == 0)
cout << endl;