0

I have a program that takes a text file and list the words and how many times they are used. It works but I can't figure out how to print out the text file. Above the sorted words and how many times they appear, I want to display the text from the file. How would I do that? I tried several things but it either does nothing or screws up the rest of the code saying there are 0 unique words. And lastly how would print out the results so they are more ... table -ish...

/*
Something like this:
Word: [equal spaces] Count:
ask   [equal spaces]  5
anger [equal spaces]  3 
*/

Thank you for any assistance you can provide me.

#include <iterator>
#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include <cctype>

using namespace std;

string getNextToken(istream &in) {
    char c;
    string ans="";
    c=in.get();
    while(!isalpha(c) && !in.eof())//cleaning non letter charachters
    {
        c=in.get();
    }
    while(isalpha(c))
    {
        ans.push_back(tolower(c));
        c=in.get();
    }
    return ans;
}

string ask(string msg) {
    string ans;
    cout << msg;
    getline(cin, ans);
    return ans;
}


int main() {


    map<string,int> words;
    ifstream fin( ask("Enter file name: ").c_str() ); //open an input stream 
    if( fin.fail() ) {
       cerr << "An error occurred trying to open a stream to the file!\n";
        return 1;
    }


    string s;
    string empty ="";
    while((s=getNextToken(fin))!=empty )
            ++words[s];

    while(fin.good()) 
        cout << (char)fin.get(); // I am not sure where to put this. Or if it is correct

    cout << "" << endl;
    cout << "There are " << words.size() << " unique words in the above text." << endl;
    cout << "----------------------------------------------------------------" << endl;
    cout << " " << endl; 

    for(map<string,int>::iterator iter = words.begin(); iter!=words.end(); ++iter)
        cout<<iter->first<<' '<<iter->second<<endl;
return 0;
}
rcwade93
  • 61
  • 1
  • 6
  • Please fix the formatting of your code. Your printing looks alright; are you sure the data `words` contains is correct? – Bartek Banachewicz Apr 27 '17 at 07:23
  • I fixed it so its easier to read. I believe so. It has given me the correct answer for a few test files. I just can't get the actual file contents to print for some reason. I tried to put 'while(fin.good()) cout << (char)fin.get(); several different places and it screwed up the rest of the code. – rcwade93 Apr 27 '17 at 07:30
  • I think the problem is that you're trying to read the input file twice (once to copy to the output, and once to break into tokens) _but you are not resetting the position in between!_ Therefore, the 2nd attempt will see an empty file. See the [`clear` and `seekg` calls in this answer](http://stackoverflow.com/a/7681612/2096401). Alternatively, you could try interleaving the printing and tokenising, but unless the files are very large, it might not be worth the effort. – TripeHound Apr 27 '17 at 08:09

2 Answers2

1

Something like this should make it:

#include <iostream>
#include <fstream>
#include <unordered_map>
#include <string>

int main( int argc, char* argv[] )
{
    std::string file;
    std::cout << "Enter file name: ";
    std::cin >> file;

    std::fstream in( file.c_str() );

    if ( in.good() )
    {
        std::unordered_map<std::string, int> words;
        std::string word;

        //Use this to separate your words it could be '\n' or anything else
        char cSeparator = ' ';
        while ( in >> word )
        {
            //Print the word
            std::cout << word << cSeparator;
            ++words[word];
        }

        std::cout << std::endl;

        //Headers Word and Count separated by 2 tabs
        std::cout << "Word:\t\tCount:" << std::endl;

        for ( auto& w : words )
            std::cout << w.first << "\t\t" << w.second << std::endl;
    }

    in.close();

    return EXIT_SUCCESS;
}

However this is assuming that the text file only contains the words, if you have other kind of stuff there, you should be able to filter it as you want.

Gerard097
  • 815
  • 4
  • 12
  • Thank you for commenting. I appreciate the code as it looks better than mine and is shorter. The only issue is that it didn't answer either of my questions. How do I print off the original text in a string format from the file? and How do I make the output into a table with a header of Word and Count? Thanks again. – rcwade93 Apr 27 '17 at 07:47
  • Do you mean printing the text sequentially as it is in your file? – Gerard097 Apr 27 '17 at 07:51
  • Yes. Sorry if I worded that incorrectly. For example if the text file contained "Peter Piper picked blah blah " how do I print out that sentence or story or whatever the file contains and display it above the sorted words table? – rcwade93 Apr 27 '17 at 07:54
  • Well Ill be damned. It worked like a charm. Thank you very much. Just one last question. How do you strip out the punctuation? – rcwade93 Apr 27 '17 at 08:12
1

I would just use a simple for loop like this:

for (int x = 0; x < words.size(); x++){
    cout >> words[x] << endl
    }

And then modify from there to get your desired format. I did notice though, that you are not returning a value for main in all paths of the above code, which should give a compile time error, but did not when I compiled it, for some reason. I would remind you that you need to have a return value for main. Unless I am misunderstanding your question. I could not run this program without creating a sample file, and so could not test it without extra work. But the program did compile. I did not expect to, because of the missing return statement. If you can make this reproduce your error without me having to create a sample file of words, ei insert the list of words into the code and minimally reproduce the error, I would be able to help you better. As it is, I hope that I helped you.

Paul Isaac
  • 84
  • 9