Counting lines from a file input? - c++

The following code is supposed to count: the lines, the characters and the words read from a text file.
Input text file:
This is a line.
This is another one.
The desired output is:
Words: 8
Chars: 36
Lines: 2
However, the word count comes out to 0 and if I change it then lines and characters come out to 0 and the word count is correct. I am getting this:
Words: 0
Chars: 36
Lines: 2
This is my code:
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main()
{
ifstream inFile;
string fileName;
cout << "Please enter the file name " << endl;
getline(cin,fileName);
inFile.open(fileName.c_str());
string line;
string chars;
int number_of_lines = 0;
int number_of_chars = 0;
while( getline(inFile, line) )
{
number_of_lines++;
number_of_chars += line.length();
}
string words;
int number_of_words = 0;
while (inFile >> words)
{
number_of_words++;
}
cout << "Words: " << number_of_words <<"" << endl;
cout << "Chars: " << number_of_chars <<"" << endl;
cout << "Lines: " << number_of_lines <<"" << endl;
return 0;
}
Any guidance would be greatly appreciated.

And because Comments are often unread by answer seekers...
while( getline(inFile, line) )
Reads through the entire file. When it's done inFile's read location is set to the end of the file so the word counting loop
while (inFile >> words)
starts reading at the end of the file and finds nothing. The smallest change to the code to make it perform correctly is to use seekg rewind the file before counting the words.
inFile.seekg (0, inFile.beg);
while (inFile >> words)
Positions the reading location to file offset 0 relative to the beginning of the file (specified by inFile.beg) and then reads through the file to count the words.
While this works, it requires two complete reads through the file, which can be quite slow. A better option suggested by crashmstr in the comments and implemented by simplicis veritatis as another answer requires one read of the file to get and count lines, and then an iteration through each line in RAM to count the number of words.
This has the same number of total iterations, everything must be counted one by one, but reading from a buffer in memory is preferable to reading from disk due to significantly faster, orders of magnitude, access and response times.

Here is one possible implementation (not tested) to use as a benchmark:
int main(){
// print prompt message and read input
cout << "Please enter the file name " << endl;
string fileName;
getline(cin,fileName);
// create an input stream and attach it to the file to read
ifstream inFile;
inFile.open(fileName.c_str());
// define counters
string line;
string chars;
int number_of_lines = 0;
int number_of_chars = 0;
vector<string> all_words;
do{
getline(inFile, line);
// count lines
number_of_lines++;
// count words
// separates the line into individual words, uses white space as separator
stringstream ss(line);
string word;
while(ss >> word){
all_words.push_back(word);
}
}while(!inFile.eof())
// count chars
// length of each word
for (int i = 0; i < all_words.size(); ++i){
number_of_chars += all_words[i].length();
}
// print result
cout << "Words: " << all_words.size() <<"" << endl;
cout << "Chars: " << number_of_chars <<"" << endl;
cout << "Lines: " << number_of_lines <<"" << endl;
return 0;
}

Related

Appending strings to text files in C++

C++ beginner here,
I am trying to append some text to a pre-written .txt file where every line there is a word.
I have been using the method ofstream and ifstream as seen below, but everytime I try to write something, it erases the file. (I am not allowed to use ios:app or simillar)
int append_new_word() {
//First I read everything on the list and save it to a string called Words_in_List
ifstream data_wordlist_in("woerterliste"); //Opens the txt file
if (!data_wordlist_in) // checks if the file exists
{
cout << "File does not exist!" << endl;
return 1;
}
string Word;
int line = 0;
string Vorhandene_Woerter;
std::getline(data_wordlist_in, Wort);
do { //line counter, goes through all lines and save it to a string
line++;
std::getline(data_wordlist_in, Word);
Words_in_List = Words_in_List + "\n" + Word;
} while (!data_wordlist_in.eof());
cout << Words_in_List << endl;
data_wordlist_in.close();
//HEre it should save the string again in the list word per word with the neu appended word
ofstream data_wordlist_out("woerterliste"); //opens ofstream
if (!data_wordlist_out)
{
cout << "File does not exist!" << endl;
return 1;
}
string new_word_in_list;
cout << "\n Insert a Word to append: ";
cin >> new_word_in_list;
data_wordlist_out << Words_in_List << endl << new_word_in_list;
data_wordlist_out.close(); //closes ofstream
}
Everytime I try I open my program it erases the list.
Your code has some minor problems, but nothing that matches your description of it.
It does line based input, which is strange because nothing in the problem description indicates that reading a line at a time is necessary.
It counts lines, again for no obvious reason.
It skips the first line (maybe this is deliberate, but if so you didn't mention that).
The loop termination is incorrect (see link in the comments).
The function is declared as returning an int but no return is made.
Here some code that addresses these problems. It reads characters not lines (using get()) which makes reading the input simpler, but essentially it's the same technique as your code.
void append_new_word()
{
string existing_content;
ifstream in("file.txt");
char ch;
while (in.get(ch))
existing_content += ch;
in.close();
cout << "enter a new word ";
string new_word;
cin >> new_word;
ofstream out("file.txt");
out << existing_content << new_word << '\n';
}

How Do I read and Output the Contents of a File and the Number of Words it Contains?

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.
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 . . .

How to read spaced string with get line() from a file?

I want to read a name like "Penelope Pasaft" all together from a file and save it to a variable "person". I have understood that I have to use the get line(file, person). But I have a problem doing it because I want also to read other variables before.
Imagine a .txt like:
1
+546343864246
Penelope Pasaft
So here is the code:
typedef struct {
string number; //I use string because it is an alphanumeric cellphone number
string person;
int identifier;
} cellphone;
ifstream entry;
entry.open(fileName.c_str());
cellphone c[10];
int j=0;
if(entry)
{
cout << "The file has been successfully opened\n\n";
while(!entry.eof())
{
entry >> c[j].identifier >> c[j].number;
getline(entry,c[j].person);
cout << "Start: " << c[j].identifier << "\nNumber: " <<
c[j].number << "\nPerson: " << c[j].person << endl << endl;
j++;
}
}
Well the problem I have it's that it doesn't seem to print or save me any data to the variable c[j].person
Problem is that your input file has empty lines in it.
If you use cin >> only, it will work OK because >> operator skips blank chars (but stops at blank chars, as you noted: can't have it all)
On the other hand, getline will read the line, even if it's blank.
I propose the following standalone code slightly modified from yours: note the loop until end of file or non-blank line.
(note: it there are spaces only in the line, it will fail)
I also replaced array by a vector, resized on the fly (more C++-ish)
#include<iostream>
#include<fstream>
#include<string>
#include<vector>
using namespace std;
typedef struct {
string number; //I use string because it is an alphanumeric cellphone number
string person;
int identifier;
} cellphone;
int main()
{
ifstream entry;
string fileName = "file.txt";
entry.open(fileName.c_str());
vector<cellphone> c;
cellphone current;
int j=0;
if(entry)
{
cout << "The file has been successfully opened\n\n";
while(!entry.eof())
{
entry >> current.identifier >> current.number;
while(!entry.eof())
{
getline(entry,current.person);
if (current.person!="") break; // stops if non-blank line
}
c.push_back(current);
cout << "Start: " << c[j].identifier << "\nNumber: " << c[j].number << "\nPerson: " << c[j].person <<endl<<endl;
j++;
}
}
return 0;
}
output:
The file has been successfully opened
Start: 1
Number: +546343864246
Person: Penelope Pasaft

c++ counting how many words in line

I'm using this code to count lines of the text, but I need to count also words and show to console how many words is in each row.
int main(int argc, char *argv[]){
ifstream f1("text.txt"); ;
char c;
string b;
int numchars[10] = {}, numlines = 0;
f1.get(c);
while (f1) {
while (f1 && c != '\n') {
// here I want to count how many words is in row
}
cout<<"in row: "<< numlines + 1 <<"words: "<< numchars[numlines] << endl;
numlines = numlines + 1;
f1.get(c);
}
f1.close();
system("PAUSE");
return EXIT_SUCCESS;
}
To count the number of lines and number of words you could try and brake it down to two simple tasks: first read each line from the text using getline() and , secondly, extract each word from a line using stringstream, after each successful (read line or extract word) action you could increment two variables that represent the number of lines and words.
The above could be implement like so:
ifstream f1("text.txt");
// check if file is successfully opened
if (!f1) cerr << "Can't open input file.";
string line;
int line_count = 0
string word;
int word_count = 0;
// read file line by line
while (getline(f1, line)) {
// count line
++line_count;
stringstream ss(line);
// extract all words from line
while (ss >> word) {
// count word
++word_count;
}
}
// print result
cout << "Total Lines: " << line_count <<" Total Words: "<< word_count << endl;

Why is the C++ StringStream skipping the first number from an input file, but showing the rest?

Okay, so I have an input file input.txtthat contains a CSV sequence: 1,1,1,2,2,3,3,4,4
and I am trying to separate it at the commas using a stringstream; however I'm getting a little problem here. For some reason the first number from the sequence is not even getting read by the stream. To show this, I created a some debugging code to see what is happening and I found out that the first number is being stored inside csvLine and every other number is being read and coverted just fine. I don't understand why just the first number is being omitted. Below is an example pic showing exactly what I mean. num should have the same exact values and Line, but it's not. It has all the values except the first one, which is being stored inside csvLine. Why is this happening?!
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main(int argc, const char * argv[]) {
ifstream file;
string line;
string csvLine; //comma seperated value line
int num = 0;
file.open(argv[1]);
if(file.is_open()) {
while(getline(file, line)) { //get the whole line and use string stream to break at commas
cout << "\nLine: " << line << endl;
//using stringstream to seperate at commas
stringstream ss(line);
while(getline(ss, csvLine, ',')) {
cout << "csvLine: " << csvLine << " " << endl;
//using stringstream to convert to int
ss >> num;
cout << "num: " << num << " " << endl;
}
}
}
return 0;
}
The problem arises since you're using getline and then extracting integer from your stringstream
You should only use getline
while(getline(ss, csvLine, ','))
{
cout << "csvLine: " << csvLine << " " << endl;
num = std::stoi( csvLine ) ;
}
When you read getline(ss, csvLine, ',') the first time it reads the number followed by the the ','. For the next numbers it just reads the comma as the number was already extracted using ss >> num. That is, the simplest fix is to only read everything up to and including the comma after the loop was executed. Since the value of string extracting the comma isn't used it makes sense to use ignore() instead of std::getline():
for (; ss >> num; ss.ignore(std::numeric_limits<std::streamsize>::max(), ',')) {
// do something with the number
}
Restructuring the loop this way has the added benefit that it is checked whether reading the number was successful.