C++ program need lines words and characters count - c++

I have an assignment where i need to count lines, words and characters from a file. I'm having a problem counting the right amount of characters and words since if it gets doubled space it counts like a character and a word.
the output should be
Example
lines words characters filename
3 5 29 testfile
Code:
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <iomanip>
using namespace std;
int main(int argc, const char * argv[]) {
string lines, words, chars, file1, file2;
ifstream infile;
ofstream outfile;
char c;
int countLines = 0;
int countChars = 0;
int countWords = 0;
cout<< "Enter the file name" << endl;
cin >> file1;
infile.open(file1.c_str());
while(!infile.eof())
{
if(infile.peek() == 1)
break;
c = infile.get();
if(c != '\n')
countChars++;
else
countLines++;
if(c == ' '|| c =='\n')
countWords++;
}
// countChars = countChars - countWords;
cout << setw(12) << countLines << setw(12) << countWords << setw(12) << countChars << endl;
infile.close();
return 0;
}

Use getline for reading file line by line
while(getline(file,str))
{
countLines++;
countChars += str.length();
countWords += CountWords(str);
}
Which file is an iofstream object and str is a string. And for counting number of words(CountWords), you have several ways. One of them is:
#include <vector>
#include <string>
#include <boost/algorithm/string/split.hpp>
int countWords(std::string str) {
vector< std::string > result;
boost::algorithm::split_regex(result, str, regex( "\\s+" ));
return result.size();
}

I believe OP's purpose to ask this question is to find out why his/her code is not working, therefore I will answer in this perspective.
counting the right amount of words
C++ define EOF(end of file) as -1, so include a check for EOF too, or you will miss a word count.
if it gets doubled space it counts like a character and a word.
You can use a boolean test to solve this, if you encountered a space, turn on the boolean, and skip if next char is a space, too.
I suppose your character count doesn't count in punctuation? so check for c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'. If your assignment count punctuation as character count too, ignore this point.
Below is a correct version code that is modified based on your code.
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <iomanip>
using namespace std;
int main(int argc, const char * argv[]) {
string lines, words, chars, file1, file2;
ifstream infile;
ofstream outfile;
char c;
bool findNextString = false;
int countLines = 0;
int countChars = 0;
int countWords = 0;
cout << "Enter the file name" << endl;
cin >> file1;
infile.open(file1.c_str());
while (!infile.eof())
{
if (infile.peek() == 1)
break;
c = infile.get();
// use the boolean to find next valid string
if (findNextString && c == ' ')
continue;
else
findNextString = false;
// there is a structure issue with your code.
// you should think of the priority of checking
// do not check by rejection, because you will count in punctuation too.
if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')
{
countChars++;
}
else if (c == '\n')
{
countLines++;
countWords++; // <- add word too
}
else if (c == ' ' || c == EOF)
{
countWords++;
findNextString = true;
}
}
cout << setw(12) << countLines << setw(12) << countWords << setw(12) << countChars << endl;
infile.close();
return 0;
}

Related

print 2nd word in a string with its size in C++

I am trying to make a program in which a user enters a string and i will print out the second word in the string with its size.
The delimiter's are space( ), comma(,) and tab( ).
I have used a character array and fgets to read from user and a character pointer that points to the first element of the array.
source code:
#include"iostream"
#include<stdio.h>
#include<string>
using namespace std;
// extract the 2nd word from a string and print it with its size(the number of characters in 2nd word)
int main()
{
char arr[30], arr1[30];
char *str = &arr1[0];
cout<<"Enter a string: ";
fgets(str, 30, stdin);
int i = 0, j, count = 1, p = 0; // count is used to find the second word
// j points to the next index where the first delimiter is found.
// p is used to store the second word found in character array 'arr'
while(*(str+i) != '\n')
{
if(*(str+i) == ' ' || *(str+i) == ',' || *(str+i) == ' ')
{
count++;
if(count == 2)
{
// stroing 2nd word in arr character array
j = i+1;
while(*(str+j) != ' ' || *(str+j) != ',' || *(str+j) != ' ')
{
arr[p] = *(str+j);
cout<<arr[p];
p++;
i++;
j++;
}
break;
}
}
i++;
}
arr[p+1] = '\0'; // insert NULL at end
i = 0;
while(arr[i] != '\0')
{
cout<<arr[i];
i++;
}
cout<<"("<<i<<")"<<endl;
return 0;
}
Help me out with this.
To start, don't use std::cin for testing. Just set a value in your code for consistency and ease of development. Use this page for a reference.
#include <iostream>
#include <string>
int main() {
std::string str("this and_that are the tests");
auto start = str.find_first_of(" ,\n", 0);
auto end = str.find_first_of(" ,\n", start + 1);
std::cout << str.substr(start, end - start);
return 0;
}
And this is still somewhat of a hack, it just depends where you are going. For instance the Boost library is rich with extended string manipulation. If you are going to parse out more than just one word it can still be done with string manipulations, but ad-hoc parsers can get out of hand. There are other tools like Boost Spirit to keep code under control.
The delimiters used when extracting from a stream depends on the locale currently in effect. One (cumbersome) way to change the extraction behaviour is to create a new locale with a special facet in which you specify your own delimiters. In the below example the new locale is used to imbue a std::stringstream instead of std::cin directly. The facet creation part is mostly copy/paste from other answers here on SO, so you'll find plenty of other examples.
#include <iostream>
#include <locale> // std::locale, std::ctype<char>
// https://en.cppreference.com/w/cpp/locale/ctype_char
#include <sstream> // std::stringstream
#include <algorithm> // std::copy_n
#include <vector> // a container to store stuff in
// facet to create our own delimiters
class my_facet : public std::ctype<char> {
mask my_table[table_size];
public:
my_facet(size_t refs = 0)
: std::ctype<char>(&my_table[0], false, refs)
{
// copy the "C" locales table to my_table
std::copy_n(classic_table(), table_size, my_table);
// and create our delimiter specification
my_table[' '] = (mask)space;
my_table['\t'] = (mask)space;
my_table[','] = (mask)space;
}
};
int main() {
std::stringstream ss;
// create a locale with our special facet
std::locale loc(std::locale(), new my_facet);
// imbue the new locale on the stringstream
ss.imbue(loc);
while(true) {
std::string line;
std::cout << "Enter sentence: ";
if(std::getline(std::cin, line)) {
ss.clear(); // clear the string stream from prior errors etc.
ss.str(line); // assign the line to the string stream
std::vector<std::string> words; // std::string container to store all words in
std::string word; // for extracting one word
while(ss>>word) { // extract one word at a time using the special facet
std::cout << " \"" << word << "\" is " << word.size() << " chars\n";
// put the word in our container
words.emplace_back(std::move(word));
}
if(words.size()>=2) {
std::cout << "The second word, \"" << words[1] << "\", is " << words[1].size() << " chars\n";
} else {
std::cout << "did not get 2 words or more...\n";
}
} else break;
}
}
#include"iostream"
#include<stdio.h>
#include<string>
#include <ctype.h>
using namespace std;
int main()
{
char c;
string str;
char emp = ' ';
cout<<"Enter a string: ";
getline (cin,str);
int j = 0, count = 1, counter = 0;
for (int i = 0; i < str.length() && count != 2; i++)
{
cout<< str[i] <<endl;
if( isspace(str[i]) || str[i] == ',' || str[i] == '\t' )
{
count++;
if(count == 2)
{
j = i+1;
while(j < str.length())
{
if (isspace(str[j]) || str[j] == ',' || str[j] == '\t')
{
break;
}
cout<<str[j];
counter++;
j++;
}
cout<<endl;
}
}
}
cout<<"size of the word: "<<counter<<endl;
return 0;
}
This is a simple answer to what you want, hope to help you.
// Paul Adrian P. Delos Santos - BS Electronics Engineering
// Exercise on Strings
#include <iostream>
#include <sstream>
using namespace std;
int main(){
// Opening Message
cout << "This program will display the second word and its length.\n\n";
// Ask for a string to the user.
string input;
cout << "Now, please enter a phrase or sentence: ";
getline(cin, input);
// Count the number of words to be used in making a string array.
int count = 0;
int i;
for (i=0; input[i] != '\0'; i++){
if (input[i] == ' ')
count++;
}
int finalCount = count + 1;
// Store each word in a string array.
string arr[finalCount];
int j = 0;
stringstream ssin(input);
while (ssin.good() && j < finalCount){
ssin >> arr[j];
j++;
}
// Display the second word and its length.
string secondWord = arr[1];
cout << "\nResult: " << arr[1] << " (" << secondWord.size() << ")";
return 0;
}

Odd Cout Behavior

I'm sorry for the initial post. This is tested and reproducible.
I'm trying to get cout to work within a fstream while loop while detecting each character its parsing, but it's exhibiting an odd behavior with the Text getting overrided by the first variable that I'm trying to put into cout.
main.cxx
#include <string.h>
#include <fstream>
#include <iostream>
#include <stdio.h>
using std::string;
using std::fstream;
using std::noskipws;
using std::cout;
int main(int argc, const char *argv[]){
char pipe;
string word; // stores the word of characters it's working on at the moment
string filename = "Directory.dat";
int type = 0; // 2 types counter, starts at 0
int newindicator = 0; // for detecting a new * for the data set
fstream fin(filename.c_str(), fstream::in);
while(fin >> noskipws >> pipe){
if(pipe == '*'){ // if the character is an asterisk
type++;
newindicator = 0;
word.clear();
}else if (pipe == '\n'){ // if the character is next line
if(newindicator == 0){ // tells the reader to know that it just finished reading a *, so it doesn't print anything.
newindicator = 1;
}else {
if(type == 1){
cout << "new word as: ";
cout << word << "\n";
}else if (type == 2){
cout << "new word as: ";
cout << word << "\n";
}
word.clear(); // clears the word string as it's reading the next line.
}
}else{
word+=pipe;
}
}
return 0;
}
Directory.dat
*
Chan
Johnathan
Joespeh
*
Betty
Lady Gaga
Output
Chanword as:
new word as: Johnathan
new word as: Joespeh
Bettyord as:
new word as: Lady Gaga
Note that how "Chan" is overriding the characters "new " on the first line, but it's fine after that. This seems to happen on every new type I'm doing, and when its recalling a new set of type. Same with Betty on the next set, which overrides "new w" with "Betty" on that cout.
Any feedback would be much appreciated. Thank you!
I suspect your input file has Windows line endings. These contain the carriage return character that's handled differently on Unix.
https://superuser.com/questions/374028/how-are-n-and-r-handled-differently-on-linux-and-windows
Thank you all for the comments and feedback. Made the changes as suggested:
Corrected
#include <string.h>
#include <fstream>
#include <iostream>
#include <stdio.h>
using std::string;
using std::fstream;
using std::noskipws;
using std::cout;
int main(int argc, const char *argv[]){
char pipe;
string word; // stores the word of characters it's working on at the moment
string filename = "Directory.dat";
int type = 0; // 2 types counter, starts at 0
int newindicator = 0; // for detecting a new * for the data set
fstream fin(filename.c_str(), fstream::in);
while(fin >> noskipws >> pipe){
if(pipe == '*'){ // if the character is an asterisk
type++;
newindicator = 0;
word.clear();
}else if (pipe == '\n'){ // if the character is next line
if(newindicator == 0){ // tells the reader to know that it just finished reading a *, so it doesn't print anything.
newindicator = 1;
}else {
if(type == 1){
cout << "new word as: ";
cout << word << "\n";
}else if (type == 2){
cout << "new word as: ";
cout << word << "\n";
}
word.clear(); // clears the word string as it's reading the next line.
}
}else{
if (pipe != '\r'){
word+=pipe;
}
}
}
return 0;
}
Output
new word as: Chan
new word as: Johnathan
new word as: Joespeh
new word as: Betty
new word as: Lady Gaga

Parsing out things surrounded by quotes in C++

I'm trying to make a parser that would only take text surrounded by quotes and place it in a new file I've already tried many times but can't figure it out it would have to take the original text out of a file by the way then place it in a new file I would like to do this in C++.
This is what I currently have:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
char current_letter;
char quote_mark = '"';
int isquote = 0;
std::cin >> current_letter;
LOOP : do
{
if(current_letter == quote_mark) {++isquote;}
if(isquote == 1 && current_letter != quote_mark) {std::cout << current_letter;}
if(isquote == 1 && current_letter == quote_mark) {--isquote;}
if(isquote == 0) {goto LOOP;}
} while (cin >> current_letter);
if(cin != current_letter) {cout << "END" <<endl;}
return(0);
It doesn't print anything now but it used to print out random stuff or just quote marks.
You could just do something like this:
string str;
getline(cin, str);
string currStr = "";
for (int i = 0; i < str.length(); i++)
{
if (str[i] != '\"') currStr += str[i];
}
cout << currStr << "\n";
This won't work if there are double quotes within the text that you want to parse however.

C++ print string one word at a time, count characters, and average of characters

how can I print a single word from a string in each line with the number of characters right next to it and the average of the characters together? I'm suppose to use a string member function to convert the object into a c string. The function countWords accepts the c string and returns an int. The function is suppose to read in each word and their lengths including the average of characters. I have done how much words are in the string except I don't know how continue the rest.
For example: super great cannon boys
super 5
great 5
cannon 6
boys 4
average of characters: 5
This is my program so far:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int countWords(char *sentence);
int main()
{
const int size=80;
char word[size];
double average=0;
cout<<"Enter words less than " <<size-1<<" characters."<<endl;
cin.getline(word, size);
cout <<"There are "<<countWords(word)<<" words in the sentence."<<endl;
return 0;
}
int countWords(char *sentence)
{
int words= 1;
while(*sentence != '\0')
{
if(*sentence == ' ')
words++;
sentence++;
}
return words;
}
Unless this is something like homework that prohibits doing so, you almost certainly want to use std::string along with the version of std::getline that works with a std::string instead of a raw buffer of char:
std::string s;
std::getline(std::cin, s);
Then you can count the words by stuffing the line into a std::istringstream, and reading words out of there:
std::istringstream buffer(s);
auto word_count = std::count(std::istream_iterator<std::string>(s),
std::istream_iterator<std::string());
To print out the words and their lengths as you go, you could (for example) use std::for_each instead:
int count = 0;
std::for_each(std::istream_iterator<std::string>(s),
std::istream_iterator<std::string>(),
[&](std::string const &s) {
std::cout << s << " " << s.size();
++count;});
This should not be far from you requirements - I only did minimal modification to your present code.
Limits :
you'd better use
string line;
getline(cin, line);
to read the line to be able to accept lines of any size
my present code assumes
no spaces at beginning or end of line
one single space between 2 words
it should be improved to cope with extra spaces, but I leave that to you as an exercise :-)
The code :
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int countWords(char *sentence, double& average);
int main()
{
const int size=80;
char word[size];
double average=0;
cout<<"Enter words less than " <<size-1<<" characters."<<endl;
cin.getline(word, size);
cout <<"There are "<<countWords(word, average)<<" words in the sentence."<<endl;
cout << "Average of the sentence " << average << endl;
return 0;
}
int countWords(char *sentence, double& average)
{
int words= 1;
int wordlen;
char *word = NULL;
while(*sentence != '\0')
{
if(*sentence == ' ') {
words++;
wordlen = sentence - word;
average += wordlen;
*sentence = '\0';
cout << word << " " << wordlen<< endl;
word = NULL;
}
else if (word == NULL) word = sentence;
sentence++;
}
wordlen = sentence - word;
average += wordlen;
cout << word << " " << wordlen<< endl;
average /= words;
return words;
}
For input : super great cannon boys
Output is :
Enter words less than 79 characters.
super great cannon boys
super 5
great 5
cannon 6
boys 4
There are 4 words in the sentence.
Average of the sentence 5
You can inspire here. Basically use std::getline to read from std::cin to std::string.
#include <iostream>
#include <string>
#include <cctype>
inline void printWordInfo(std::string& word) {
std::cout << "WORD: " << word << ", CHARS: " << word.length() << std::endl;
}
void printInfo(std::string& line) {
bool space = false;
int words = 0;
int chars = 0;
std::string current_word;
for(std::string::iterator it = line.begin(); it != line.end(); ++it) {
char c = *it;
if (isspace(c)) {
if (!space) {
printWordInfo(current_word);
current_word.clear();
space = true;
words++;
}
}
else {
space = false;
chars++;
current_word.push_back(c);
}
}
if (current_word.length()) {
words++;
printWordInfo(current_word);
}
if (words) {
std::cout << "AVERAGE:" << (double)chars/words << std::endl;
}
}
int main(int argc, char * argv[]) {
std::string line;
std::getline(std::cin, line);
printInfo(line);
return 0;
}
Going along the lines of what you already have:
You could define a countCharacters function, like your countWords:
int countCharacters(char *sentence)
{
int i;
char word[size];
for(i = 0; sentence[i] != ' '; i++) //iterate via index
{
word[i] = sentence[i]; //save the current word
i++;
}
cout <<word<< <<i<<endl; //print word & number of chars
return i;
}
which you can call inside your countWords function
int countWords(char *sentence)
{
int words = 1;
for(int i; sentence[i] != '\0';) //again this for loop, but without
//increasing i automatically
{
if(sentence[i] == ' ') {
i += countCharacters(sentence[++i]); //move i one forward to skip
// the space, and then move
// i with the amount of
// characters we just counted
words++;
}
else i++;
}
return words;
}

Need to check if the string is the same when read backwards [duplicate]

This question already has answers here:
to find if a given string is palindrome or is not palindrome
(10 answers)
Closed 8 years ago.
I have no clue what is wrong here. I'm a totally new though.
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <tchar.h>
#include <string>
using namespace std;
int main()
{
int string_length;
string word, wordb;
cout << "Type in a word\n";
cin >> word;
string_length = word.length();
for (int i=1; i < (string_length+1); i++)
wordb = wordb + word.at(i);
if (word == wordb)
cout << "The word is the same in any direction.\n";
else
cout << "The word is not the same in any direction.\n";
return 0;
}
Sorry if it's obvious.
you don't have to "construct" the wordb from word, you can directly compare the letters one by one in one iteration:
for (int i=0; i < string_length; i++) {
if letter_in_pos[i] == letter_in_pos[string_length-i-1]
looks good, do nothing
else
break! word is not a palindrome!
}
and finally, if the word is a real palindrome, you only need to go to the middle of the word (since it's symmetric).
chris suggested the use of std::equal. Here is an example of how that would look like:
#include <string>
#include <algorithm>
#include <iostream>
bool is_palindrome(const std::string& s)
{
return std::equal(s.begin(), s.begin() + s.size()/2, s.rbegin());
}
int main()
{
std::string word;
std::cout << "Type in a word\n";
std::cin >> word;
if (is_palindrome(word))
std::cout << "The word is the same in any direction.\n";
else
std::cout << "The word is not the same in any direction.\n";
}
The simplest way is to write
if ( word == string( word.rbegin(), word.rend() ) )
//...
or
wordb.assign( word.rbegin(), word.rend() );
if ( word == wordb )
//...
As for your approach then the correct loop will look as
for ( string::size_type i = word.length(); i != 0; )
wordb.push_back( word[--i];
or
for ( string::size_type i = word.length(); i != 0; )
wordb += word[--i];
The easiest way I know to do this would be to use the simple logic of A[DeltaX]==B[-DeltaX], While DeltaX <= 1/2 Length. Where A is your first Character, B is your last character, and DeltaX is your step, which should never take you past 1/2 the length of the string (as you will be comparing the first half to the second half).
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <tchar.h>
#include <string>
using namespace std;
int main()
{
int string_length;
int last_character;
bool found_mirror = true;
cout << "Type in a word\n";
cin >> word;
string_length = word.length();
// if the char count is less that 2 than technically it's true
if (string_length < 2)
return true;
last_character = string_length - 1;
for (int i = 0; i <= (string_length / 2); i++)
{
if (word[i] != word[last_character - i])
{
found_mirror = false;
break;
}
}
if (found_mirror)
cout << "The word is the same in any direction.\n";
else
cout << "The word is not the same in any direction.\n";
return 0;
}