How to use function definitions to open, read, and close a file - c++

We are asked to open a text file that contains a sentence and go through all the letters and whitespace in the file and count how many of each ascii character there are.
When I had all my information in the main function it worked fine. I just can't figure out how to call them all successfully in the main. The output should look like:
15 words
6 a
3 d
6 e
3 g
3 h
3 i
15 l
6 o
6 r
3 s
3 t
3 w
I achieved this output when again everything was in the main function so now it's just a matter of getting it like this with my function definitions.
My Code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//prototypes
//int openFile();
void readFile(ifstream &in);
void closeFile(ifstream &in);
//definitions
int openFile()
{
ifstream in;
in.open("word_data.txt");
}
void readFile(ifstream &in)
{
//store the frequency of the letters
int letters[128];
//declare variables
char let;
int wordCount = 0;
//for loop to initialize all counts to zero
for (int i = 0; i < 128; i++)
{
letters[i] = 0;
}
//get letters until we reach end of file
//whitespace = wordCount++;
let = in.get();
while (let != EOF)
{
if (let == ' ')
wordCount++;
//change to lowercase
let = tolower(let);
letters[let]++;
let = in.get();
}
//output
//num words
cout << wordCount + 1 << " words" << endl;
//count how many of each letter there are & print to screen in alphabetical order
for (char let = 'a'; let <= 'z'; let++)
{
if (letters[let] != 0)
{
cout << letters[let] << " "<< let <<endl;
}
}
}
void closeFile(ifstream &in)
{
in.close();
}
int main()
{
openFile();
readFile(in);
closeFile(in);
return 0;
}

The problem is with your openFile() function. It creates a local ifstream only, it does not open an ifstream that is accessible to the other functions.
Try this instead:
#include <iostream>
#include <fstream>
#include <string>
#include <cctype>
using namespace std;
//prototypes
void openFile(ifstream &in);
void readFile(ifstream &in);
void closeFile(ifstream &in);
//definitions
void openFile(ifstream &in)
{
in.open("word_data.txt");
}
void readFile(ifstream &in)
{
//store the frequency of the letters
int letters[128] = {};
//declare variables
char ch;
int wordCount = 0;
//get letters until we reach end of file
while (in.get(ch))
{
if (ch == ' ')
wordCount++;
//change to lowercase
ch = static_cast<char>(tolower(static_cast<unsigned char>(ch)));
letters[ch]++;
}
//output
//num words
cout << wordCount + 1 << " words" << endl;
//count how many of each letter there are & print to screen in alphabetical order
for (ch = 'a'; ch <= 'z'; ch++)
{
if (letters[ch] != 0)
{
cout << letters[ch] << " " << ch <<endl;
}
}
}
void closeFile(ifstream &in)
{
in.close();
}
int main()
{
ifstream in;
openFile(in);
readFile(in);
closeFile(in);
return 0;
}
With that said, you might consider using a std::map to track your frequencies, rather than using an int[] array. And using operator>> to read whole words at a time:
#include <map>
...
void readFile(ifstream &in)
{
//store the frequency of the letters
map<char, int> letters;
//declare variables
string word;
int wordCount = 0;
//get letters until we reach end of file
while (in >> word)
{
++wordCount;
//for(size_t idx = 0; idx < word.size(); ++idx)
//{
// char ch = word[idx];
for(char ch : word)
{
//change to lowercase
ch = static_cast<char>(tolower(static_cast<unsigned char>(ch)));
if (ch >= 'a' && ch <= 'z')
letters[ch]++;
}
}
//output
//num words
cout << wordCount << " words" << endl;
//count how many of each letter there are & print to screen in alphabetical order
//for (map<char, int>::iterator iter = letters.begin(); iter != letters.end(); ++iter)
//{
// cout << iter->second << " " << iter->first << endl;
//}
for (auto &elem : letters)
{
cout << elem.second << " " << elem.first << endl;
}
}

Related

How do I read a file faster in c++

I am trying to make a program which takes a text file with words and letters with which it outputs the longest word it can create with the letters you provided.
This is the code:
#include <algorithm>
#include <fstream>
#include <iostream>
#include <unordered_set>
#include <cstring>
#include <chrono>
using namespace std;
using namespace std::chrono;
bool can_make (string word, unordered_set<char> letters);
int main (int argc, char* argv[]) {
fstream dict_file(argv[1]);
unordered_set<char> letters;
unordered_set<string> words;
string word;
size_t max_len = 0;
for (int i = 2; i < argc; i++) {
for (int j = 0; j < strlen(argv[i]); j++) {
letters.insert(argv[i][j]);
}
}
while (getline(dict_file, word)) {
if (word.length() > max_len && can_make(word, letters)) {
words.clear();
max_len = word.length();
words.insert(word);
} else if (word.length() == max_len && can_make(word, letters)) {
words.insert(word);
}
}
dict_file.close();
auto start = high_resolution_clock::now();
cout << "Words: ";
for (string word : words) {
cout << word << " ";
}
cout << "\n" << endl;
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
cout << "Time elapsed: " << (duration.count()) << " microseconds" << endl;
cout << endl;
return 0;
}
bool sort_func (string first, string second) {
return first.length() > second.length();
}
bool can_make (string word, unordered_set<char> l) {
for (char i : word) {
if (l.find(i) == l.end()) return false;
}
return true;
}
I want to make the code as fast as possible, and the only thing that is taking a long time is the file reading. Is there a way to read a file faster?

How do I convert a string I get from a function from an external file to all upper case [duplicate]

This question already has answers here:
Convert a String In C++ To Upper Case
(31 answers)
Closed 7 years ago.
I am writing a program that can count the number of times a word is found in a external file. The words that are to be searched for are also in an external file but I am able to retrieve those just fine. I realised that it will only update the value of count if the word exactly matches. So for example if I was searching for the word "School" and the word "school" was in the textfile I don't think the value of count would be changed. I also think that count wouldn't be changed if the word to be search for was "SCHOOL" and the word in the textfile was "school". So how do I edit my if statements so that for example the word "school" would match "SCHOOL" AND "School"?
This is my main function:
#include <iostream>
#include "ReadWords.h"
#include "Writer.h"
#include <cctype>
#include <string>
using namespace std;
int main() {
int x = 9;
int count = 0;
int count0;
int count1;
int count2;
int count3;
int count4;
int count5;
int count6;
int count7;
int count8;
int count9;
int scount;
const int size = 10;
string word_search[size];
string word;
cout << "Please enter a filename: " << flush;
char filename[30];
cin >> filename;
ReadWords reader(filename);
while (reader.isNextWord()){
count = count + 1;
reader.getNextWord();
}
cout << "There are: " << count << " words in the play" << endl;
cout << "Please enter the name of the file with the search words: " << flush;
char filename1[30];
cin >> filename1;
ReadWords reader1(filename1);
scount = 0;
while (reader1.isNextWord()) {
word_search[scount] = reader1.getNextWord();
++scount;
}
cout << "" << endl;
while (reader.isNextWord()) {
This is where I attempted to convert the input to upper case to see if the word matches the uppercase version of itself but this didn't work. Here I also need to check if the word matches itself if the first letter is capital?
if (reader.getNextWord() == word_search[0] || toupper(reader.getNextWord()) == word_search[0]) {
count0 = count0 + 1;
}
if (reader.getNextWord() == word_search[1]) {
count1 = count1 + 1;
}
if (reader.getNextWord() == word_search[2]) {
count2 = count2 + 1;
}
if (reader.getNextWord() == word_search[3]) {
count3 = count3 + 1;
}
if (reader.getNextWord() == word_search[4]) {
count4 = count4 + 1;
}
if (reader.getNextWord() == word_search[5]) {
count5 = count5 + 1;
}
if (reader.getNextWord() == word_search[6]) {
count6 = count6 + 1;
}
if (reader.getNextWord() == word_search[7]) {
count7 = count7 + 1;
}
if (reader.getNextWord() == word_search[8]) {
count8 = count8 + 1;
}
if (reader.getNextWord() == word_search[9]) {
count9 = count9 + 1;
}
}
cout << "Please enter the name of the file to write to: " << flush;
char filename2[30];
cin >> filename2;
Writer reader2(filename2);
cout << "File has been written too.." << endl;
reader2.writeInt(count);
reader2.writeString("Hello my name is Joshua Ogunnote");
return 0;
}
This is a separate file where some of my functions are declared:
#include "ReadWords.h"
#include <cstring>
#include <iostream>
using namespace std;
void ReadWords::close(){
wordfile.close();
}
ReadWords::ReadWords(const char *filename) {
wordfile.open(filename);
if (!wordfile) {
cout << "could not open " << filename << endl;
exit(1);
}
}
string ReadWords::getNextWord() {
string n;
if(isNextWord()){
wordfile >> n;
int len = n.length();
for(int i = 0; i < len ; i++) {
if (ispunct(n[i]))
{
n.erase(i--, 1);
len = n.length();
}
}
cout << n << endl;
return n;
}
}
bool ReadWords::isNextWord() {
if (wordfile.eof()) {
return false;
}
return true;
}
If you're just using English, a simple tolower() transform will do.
std::string tolower( std::string s )
{
for (char& c : s) c = std::tolower( c );
return s;
}
Now you can compare them:
if (tolower( "Hello" ) == tolower( "HELLO" ))
If you are working with Unicode, you should perform a conversion called case folding on the text, and compare the resulting string data.

Print the alphabet letters that are not in the line c++

So, what I'm trying to do is, open and read a file, but read only the first line. I have already done this part. I have to read each character on that line and then I need to print the alphabet letters that are not found in that line.
Let's say the line was:
a b c D E f G H I j k L M n o
So, I will have to print the letters from p-z, because they are not in the line.
So, how will get the letters that are not in the line?!
This is what I have so far:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
using namespace std;
int main(int argc, char *argv[]){
if(argc < 2){
cerr << "Usage: pangram <filename>" << endl;
return 0;
}
ifstream infile(argv[1]);
if (infile.good() == false){
cerr << "Error opening file[" << argv[1] << "]" << endl;
return 1;
}
char ch;
string line;
int a[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};
int brk = 0;
while(infile.good()){
if(brk == 0) {
getline(infile, line);
for(int i=0; i <= line[i]; i++){
if(isalpha(line[i])) {
if(line[i] == )
cout << line[i] << endl;
}
}
}
brk ++;
if(brk == 1) {
break;
}
}
}
Here's a slightly modified version of your solution. I'm intentionally using a stack allocation of 26 bools instead of bitset so it's easier to comprehend.
bool letter_was_seen[26] = {}; // initialize an array to hold 26 bools (A..Z) all to false
getline(infile, line); // read a line into a string
size_t len = line.size();
for (size_t i = 0; i < len; i++)
{
char ch = ::toupper(line[i]); // convert to upper case
if ((line[i] >= 'A') && (line[i] <= 'Z')) // is it a valid letter A..Z ?
{
letter_was_seen[ch - 'A'] = true; // mark it's place in the array as "seen"
}
}
// now print the letters not seen within the line
for (char i = 'A'; i <= 'Z'; i++)
{
int index = (int)(i - 'A');
if (letter_was_seen[index] == false)
{
cout << i; // print the letter not seen
}
}
cout << endl; // print end of line to flush output
Another possible solution,
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
int main() {
deque<char> allChars(26);
iota(allChars.begin(), allChars.end(), 'a');
char readString[] = "test xyz";
for (char& c : readString) {
allChars.erase(remove(allChars.begin(), allChars.end(), c),
allChars.end());
}
cout<<"Not removed: ";
for (char& c : allChars) {
cout<<c<<" ";
}
cout<<endl;
}

Why my lexical analyzer does not recognizes Quotes ""

I hope someone can help me with this issues. I am creating a HTML lexical analyzer in c++. According to the teacher I am supposed to have 3 files. one header and 2 main .cpp and it should be able to read a file
This is my file try.txt
<<<<<Hello there <H1 style=”BOLD”>header!!</H1>
<<
<< =
This is my header
#ifndef tokens_h
#define tokens_h
#include <string>
#include <iostream>
enum tokens {TEXT, LANGLE = 60, RANGLE = 62, SLASH = 47, ID, EQ = 61, QSTRING = 34, OTHER, END};
/* TEXT = 0
LANGLE = 60
RANGLE = 62
SLASH = 47
ID = 48
EQ = 61
QSTRING = 34
OTHER = 36
END = 36
*/
int getToken(std::istream *br, std::string a);
#endif
This is my main.cpp
#include <iostream>
#include <fstream>
#include <vector>
#include "tokens.h"
using namespace std;
int main(int argc, char *argv[])
{
//defineTokens();
istream *br;
ifstream infile;
string output;
int a;
vector<int> count;
int langle = 0;
string line;
if(argc == 1){
while(cin.good() ){ //Get continous input
br = &cin;
getline(cin,line);
getToken(br,line);
}
}
else if(argc != 2){
return 1;
}else{
infile.open(argv[1]);
if( infile.is_open()){
br = &infile;
while(!infile.eof()){
getline(infile,output);
getToken(br,output);
}
}
else{
cout << argv[1] << "Can't Be Opened" << endl;
return 1;
}
}
}
and this is my tokens.cpp where I print the results
#include <iostream>
#include <stdio.h>
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>
#include <map>
#include <utility>
#include "tokens.h"
using namespace std;
void compar(int ch)
{
vector<int> text;
vector<int> langle;
//string langle;
vector<int> rangle;
vector<int> slash;
vector<int> id;
vector<int> eq;
vector<int> qstring;
vector<int> other;
map <string, int> result;
int c=0;
int d=0;
int sum;
string r;
switch(ch){
case 60:static int countlangle = 0;
countlangle ++;
result["LANGLE"]= countlangle;
cout << "LANGLE: " << result["LANGLE"] << " ";
break;
case 62:static int countrangle = 0;
countrangle ++;
result["RANGLE"]= countrangle;
cout << "RANGLE: " << result["RANGLE"] << " ";
break;
case 47:static int countslash = 0;
countslash ++;
result["SLASH"]= countslash;
cout << "SLASH: " << result["SLASH"] << " ";
break;
case 61:static int counteq = 0;
counteq ++;
result["EQ"]= counteq;
cout << "EQ: " << result["EQ"] << " ";
break;
case 34:static int countqstring = 0;
countqstring ++;
result["QSTRING"]= countqstring;
cout << "QSTRING: " << result["QSTRING"] << " ";
break;
}
}
int getToken(istream *br, string a)
{
int b;
string d = "no";
string f = "no";
string r;
vector<char> st;
vector<string> trial;
vector<int> countr;
vector<int> countl;
vector<char> quotes;
string ans;
int x=0;
r = a;
cout << a[27];
int found;
found = a.find('\"');
cout << found<<"XXxxxxxX";
for(int i = 0; i< a.length();i++){ //read entire string
if(a[i] == '<'){
// cout << LANGLE << " ";
d="yes";
x +=1;
countr.push_back(LANGLE);
//cout << count.size();
//cout << x;
compar(LANGLE);
b =LANGLE;
// return LANGLE;
}
else if(a[i]== '>' && d == "yes"){
f = "yes";
b = RANGLE; //assing to the int variable the value from the enum header
compar(RANGLE);
}
else if(a[i]== '/' && d == "yes"){
compar(SLASH);
}
else if(a[i] == '=' && d == "yes"){
compar(EQ);
}
else if(a[found] == '\"' && d == "yes"){
// for(int k =0;k < quotes.size();k++)
//cout << r[found] <<"XXX";
compar(QSTRING);
}
}
return 0;
}
The program reads <>= without a problem but when I try to read a '\"' with cout << a[27];
I get this: ?
if I print cout << a;
i get <<<<<Hello there <H1 style=”BOLD”>header!!</H1> // this is the string I am trying to read
when I use found = a.find('\"'); it gives me a -1
My question is why my program cannot recognized quotes? is it the way I am reading the file?
thanks in advance
Your file contains:
”
whereas your lexer looks for:
"
These are distinct.

C++ "Count the number of collisions at each slot in the hash table"

I'm suppose to create a Dictionary as a Hash Table with Linked List to spell check a text document. I read in the file "words.txt" to create the dictionary. Also, I have to count/display the number of collisions at each slot in the hash table when I load in the dictionary "words.txt"
I'm given the source code for the HashTable Class with Linked List as followed :
hashtable.cpp (#include "listtools.cpp" since its using templates)
#include <iostream>
#include <string>
#include "listtools.h"
#include "listtools.cpp"
#include "hashtable.h"
using LinkedListSavitch::Node;
using LinkedListSavitch::search;
using LinkedListSavitch::headInsert;
using namespace std;
#define HASH_WEIGHT 31
namespace HashTableSavitch
{
HashTable::HashTable()
{
for (int i = 0; i < SIZE; i++)
{
hashArray[i] = NULL;
//array for collisons
collisionArray[i] = 0;
}
}
HashTable::~HashTable()
{
for (int i=0; i<SIZE; i++)
{
Node<string> *next = hashArray[i];
while (next != NULL)
{
Node<string> *discard = next;
next = next->getLink( );
delete discard;
}
}
}
unsigned int HashTable::computeHash(string s) const
{
unsigned int hash = 0;
for (unsigned int i = 0; i < s.length( ); i++)
{
hash = HASH_WEIGHT * hash + s[i];
}
return hash % SIZE;
}
bool HashTable::containsString(string target) const
{
int hash = this->computeHash(target);
Node<string>* result = search(hashArray[hash], target);
if (result == NULL)
return false;
else
return true;
}
void HashTable::put(string s)
{
int count = 0;
int hash = computeHash(s);
if (search(hashArray[hash], s) == NULL)
{
// Only add the target if it's not in the list
headInsert(hashArray[hash], s);
}
else
{
collisionArray[hash]++;
}
void HashTable::printArray()
{
int number;
for(int i = 0; i < SIZE; i++)
{
number = collisionArray[i];
cout << "----------------\n";
cout << "index = " << i << endl;
cout << "Collisions = " << number << endl;
cout << "----------------\n";
}
}
} // HashTableSavitch
my main.cpp file
#include <iostream>
#include <fstream>
#include <cctype>
#include <algorithm>
#include <cstring>
#include <string>
#include "hashtable.h"
using namespace std;
using HashTableSavitch::HashTable;
void upToLow(string & str);
void removePunct(string & str);
int main()
{
HashTable h;
string currWord;
string word;
int countMisspelled = 0;
int countCorrect = 0;
//Get input from words.rtf
ifstream dictionary("words.txt");
//File checking
if (dictionary.fail())
{
cout << "File does not exist" << endl;
cout << "Exit program" << endl;
}
//Create the dictionary as a hash table
while(dictionary >> currWord)
{
h.put(currWord);
}
dictionary.close();
//display collisions
h.printArray();
//Get input from gettysburg_address.txt
ifstream input("gettysburg_address.txt");
//File checking
if (input.fail())
{
cout << "File does not exist" << endl;
cout << "Exit program" << endl;
}
//Spell check gettysburg_address.txt
cout << "Misspelled words : " << endl;
cout << endl;
//If a word is not in the dictionary assume misspelled
while(input >> word)
{
removePunct(word);
upToLow(word);
if(h.containsString(word) == false)
{
countMisspelled++; // Increment misspelled words count
cout << word << " ";
if(countMisspelled % 20 == 0) // Display misspelled words 20 per line
{
cout << endl;
}
}
else
{
countCorrect++; // Increment correct words count
}
}
input.close();
cout << endl;
cout << endl;
cout << "Number of misspelled words : " << countMisspelled << endl;
cout << "Number of correct words : " << countCorrect << endl;
return 0;
}
/*Function to convert uppercase letters to lowercase*/
void upToLow(string & str)
{
for (unsigned int i = 0; i < strlen(str.c_str()); i++)
if (str[i] >= 0x41 && str[i] <= 0x5A)
str[i] = str[i] + 0x20;
}
/*Function to remove punctuation from string*/
void removePunct(string & str)
{
str.erase(remove_if(str.begin(), str.end(), static_cast<int(*)(int)>(&ispunct)),str.end());
}
Is there a simple way to count the number of collisions at each slot when loading in "words.txt" ? If I implement a count variable in the "put" function I can get the total number of collisions, but I'm not quite sure how to count/display the number of collisions at each slot of the hash table. Any help/tips is appreciated.
EDIT :
Followed Joe's advice and now I'm wondering how I could display the number of collisions at each slot. I made a void function to do just that but it displays the number of collisions at each slot to be 0. Anyone know what I should do?
Probably the simplest way is declare an array in an appropriate place
int collisionArray[SIZE];
initialize it to 0 in HashTable::HashTable()
HashTable::HashTable()
{
for (int i = 0; i < SIZE; i++)
{
hashArray[i] = NULL;
collisionArray[i] = 0;
}
}
then increment the appropriate element when a collision is found
void HashTable::put(string s)
{
int count = 0;
int hash = computeHash(s);
if (search(hashArray[hash], s) == NULL)
{
// Only add the target if it's not in the list
headInsert(hashArray[hash], s);
collisionArray[hash]++;
}
}