0

I am attempting to write a program for homework which reads the contents of a notepad file and displays the contents and the number of words int he file. My code currently outputs nothing when I enter the name of the names of files I am using to test the program, and the input validation while loop I inserted does not function either.

#include <iostream>
#include <fstream>
using namespace std;

int main()
{
//Declare needed variables
string fileName, contents;

int wordCount = 0;
ifstream inData;

//Display program info
cout << "*** A SIMPLE FILE PROCESSING PROGRAM ***" << endl;

//Prompt user input
cout << "Enter a filename or type quit to exit: ";
cin >> fileName;

inData.open(fileName.c_str());

//Inform the user when their input is invalid and ask them to input another 
file name
while (!inData)
{
    inData.clear();
    inData.ignore(200, '\n');
    cout << "File not found. Please type a correct file name." << endl;
    cin >> fileName;
    inData.open(fileName.c_str());
}

inData >> contents;

//Read and output the contents of the selected file
while (inData)
{
    cout << fileName << " data\n";
    cout << "***********************" << endl;
    inData >> contents;
    wordCount++;
    cout << contents << endl;
    inData >> contents;
}

//Display the number of words in the file
cout << "***********************" << endl;
cout << fileName << " has " << wordCount << " words." << endl;

inData.close();

return 0;
}

The code compiles in its current state [but does not produce the desired outcome.

Mariofan717
  • 45
  • 1
  • 4
  • Compiling only means that it is syntactically correct, not that it's logically correct. Stepping through the code in your debugger will help you figure out why its not working as expected. – Ken White Jul 13 '19 at 00:34
  • See [why `while (!inData.eof())` is wrong](https://stackoverflow.com/q/5605125/9254539). Also, `ifstream` functions work just fine with `std::string`, no need to use `c_str`. Stream destructors will automatically close files when the stream goes out of scope, so you don't have to explicitly close it. What do you think this loop does? `while (fileName != "quit")` See https://ericlippert.com/2014/03/05/how-to-debug-small-programs/ – BessieTheCookie Jul 13 '19 at 00:41

1 Answers1

0

I will show you one of the many possible solutions.

But I would not recomend, to check the validity of a filename in a loop. You will give the user no chance to escape. Hence, I propose to open the file, and, if that does not work, show an error message and quit.

Then, what sounds easy in the beginning like, count the words, is not really that easy. What is a word? Characters only, or characters mixed with digits or even an underscore in it like for C++ variable names? Needs to be defined.

Additionally you may have separators like commas or one and more other white spaces. So a line like "Hello,,,,World" cannot be so easily counted. If you try to read the 2 words, then you will see a surprise.

    std::string s1{};
    std::string s2{};
    std::istringstream iss("Hello,,,,World");
    iss >> s1 >> s2;

Will read everything in s1!

The solution is that we define clearly what a word is. And this we will do with a std::regex. In the below example we use characters, digits and _

Then we use the regex_iterator to find all occurences of the regex (the word) in the line. We substract the end from the beginning with std::distance, which will give us the count of the words.

Then we give an output to the user in whatever format.

It may seem complicated. But it is precise. And rather flexible. Try to anaylze line by line and you will understand it.

Please see:

#include <iostream>
#include <string>
#include <regex>
#include <fstream>
#include <iomanip>

int main()
{
    // Get a filename from the user
    std::cout << "Enter a filename:\n";
    std::string filename{};  std::cin >> filename;

    // Try to open and read the file
    std::ifstream fileStream(filename);
    if (fileStream) {
        // We will count all words
        size_t numberOfWordsOverall{ 0 };

        // We will also count the lines in the file
        size_t lineCounter{ 1 };

        // Define, what a word is. In this case: Characters, Digits and _
        std::regex regexForWord("[\\w\\d_]+");

        // Read all lines in file
        std::string line{};
        while (std::getline(fileStream, line)) {

            // Count the numbers of words in one line
            const size_t numberOfWordsInLine = std::distance(
                std::sregex_token_iterator(line.begin(), line.end(), regexForWord, 1),
                std::sregex_token_iterator()
            );
            // Update the overall word counter
            numberOfWordsOverall += numberOfWordsInLine;

            // Show result to user
            std::cout << "# " << std::left << std::setw(2) << lineCounter++ << "   (Words in line: "<< std::setw(2) << numberOfWordsInLine <<
                " Words overall: " << std::setw(4) << numberOfWordsOverall << ")  Line content --> " << line << '\n';
        }
    }
    else {
        std::cerr << "Could not open file '" << filename << "'\n";
    }
    return 0;
}

Hope this helps . . .

Armin Montigny
  • 7,879
  • 3
  • 11
  • 29