user12230466
user12230466

Reputation: 27

A program that finds the word count and letters in a sentence

Write a program that will read in a line of text and output the number of words in the line and the number of occurrences of each letter. Define a word to be any string of letters that is delimited at each end by either whitespace, a period, a comma, or the beginning or end of the line. You can assume that the input consists entirely of letters, whitespace, commas, and periods. When outputting the number of letters that occur in a line, be sure to count uppercase and lowercase versions of a letter as the same letter. Output the letters in alphabetical order and list only those letters that occur in the input line. For example, the input line I say Hi. should produce output similar to the following: 3 words 1 a 1 h 2 i 1 s 1 y

#include<iostream>
#include<cstring>
#include<cctype>
using namespace std;

int main()
{
  string input;
  cout<<"Enter a sentence: ";
  getline(cin,input);
  int count[26] = {0},i,wordCount=0;
  for(i = 0; i< input.size();i++){
  if(((input[i]>='a' && input[i] <= 'z')||(input[i]>='A' && input[i] <= 'Z'))&&(input[i+1]=='.'||input[i+1]
  ==','||input[i+1]=='\0'))
  wordCount++;
  if(input[i]>='a' && input[i] <= 'z')
  count[input[i]-'a']++;
  if(input[i]>='A' && input[i] <= 'Z')
  count[input[i]-'A']++;


  }
  char x = input[input.size()-1];
  if(x != '.' && x != 'z' && x!= '\0')
  wordCount++;
  cout<<endl<<wordCount<<" words "<<endl;
  for(i=0; i<26; i++)
  {
    if(count[i]>0)
    cout<<count[i]<<" "<<(char)('a'+i)<<endl;
  }

}

For example, it runs and everything but prints the wrong word size. EXAMPLE: Enter a sentence: I am confused please help

2 words 2 a 1 c 1 d 4 e 1 f 1 h 1 i 2 l 1 m 1 n 1 o 2 p 2 s 1 u

Upvotes: 0

Views: 11957

Answers (3)

zdf
zdf

Reputation: 4808

You must learn how to decompose a problem in sub-problems. The following is not a full answer, but it should guide you to it.

  1. Since the input is made of only valid characters, you can assume that everything except for letters and new-line is a separator.

  2. You could also write a function that reads a single word until it reaches the end of line. Then you could use it like this:

    int main()
    {
      while (get_word())
        ;
    
      cout 
        << "words: " << word_count << endl
        << "letters: " << letter_count;
    }
    
  3. The function would use the following library functions:

    • istream::get - gets the next character from stream;
    • ::isalpha - returns true if the argument is a letter;
    • istream::putback - puts back, in the stream, a character.

int word_count, letter_count;

bool get_word()
{
  char c;

  // skip all characters except for letters and new-line
  while (cin.get(c) && !isalpha(c) && '\n' != c)
    ;

  // did we reach the end of line?
  if (!cin || '\n' == c)
    return false; // we read all the words

  //
  string word{ c }; // add the first read character to word
  while (cin.get(c) && isalpha(c)) // while the read character is a letter add it to the word
    word += c;

  // the last read character is not a letter, so put it back in stream
  cin.putback(c);

  // now we have a word: count it
  ++word_count;

  // count letters in word
  letter_count += word.length();

  // we still have words to read
  return true;
}

Run it.

Upvotes: 0

A M
A M

Reputation: 15277

The answers that I saw up to now are IMHO somehow too complex. And especially look like C with some C++ extensions.

I would like to show a "more-modern" C++ solution, which takes advantage of using C++ algorithms and modern language features.

With that, counting the words in a std::string is one statement, a typical one-liner. The same is valid for counting the characters.

Counting characters has a well known and widely spread solution. Simply use a std::map, add the elements as key, using the index operator, and increment the value for the key. You can google for it and find tons of examples.

For the special requirements of this task, we additionally check, to put only alpha characters in the std::map. And, we make sure that everthingy is lowercase.

The whole counting boils down to:

std::for_each(test.begin(), test.end(), 
    [&counter](const char c) { if (std::isalpha(c)) counter[std::tolower(c)]++;  });

We iterate over each character in the std::string, check, if it is alpha, and if so, convert it to lower case, put it in the map and count it.

OK, simple.

Now, we want to count the words. For that we will use also an iterator, that iterates over all words in the string. As you know, an iterator (or better said, its underlying container) has a "begin" and an "end". And if you subtract the end position from the start position, then you always have the number of elements.

Example: if you have a std::vector, then you know that the distance between the std::vector's begin() and end() is the number of elements in the vector. OK, clear.

Now, how can we iterate over all words in a std::string? For this, C++ has a std::sregex_token_iterator. This will iterate over all elements that follow a given pattern. The pattern will be defined in a std::regex. The result is again an ultra simple statement, again, a one-liner (one statement):

std::distance(
    std::sregex_token_iterator(test.begin(), test.end(), re, 1),
    std::sregex_token_iterator()) 

Please notice the simplicity of this solution for an assumed difficult task. We will show the result on the display. And also the character counts. For the latter we use a range based for loop and extract the elements from the std::map via structed bindings.

The result is a very short solution fullfilling the requirements in an elegant C++ way.

#include <iostream>
#include <iterator>
#include <algorithm>
#include <cctype>
#include <regex>
#include <map>

const std::regex re(R"([\w]+)");
const std::string test{ "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, "
                        "sed diam nonumy eirmod tempor invidunt ut labore et dolore "
                        "magna aliquyam erat, sed diam voluptua. At vero eos et "
                        "accusam et justo duo dolores et ea rebum. Stet clita kasd "
                        "gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." };

int main() {
    // Count the number of characters
    std::map<char, size_t> counter{};
    std::for_each(test.begin(), test.end(), [&counter](const char c) { if (std::isalpha(c)) counter[std::tolower(c)]++;  });

    // Print the number of words
    std::cout << "Number of Words: " 
        <<  std::distance(std::sregex_token_iterator(test.begin(), test.end(), re, 1), std::sregex_token_iterator()) 
        << "\n\nCount of characters:\n\n";

    // Show character count on display
    for (const auto& [character, count] : counter) std::cout << character << " -> " << count << "\n";

    return 0;
}

What a pity that nobody will read it . . .

Upvotes: 0

Somil  Garg
Somil Garg

Reputation: 474

Instead of using '\0' for checking whitespace use ' '.
'\0' represents NUL termination in strings.
In C++ strings are not '\0' terminated.
'\0' value is 0 in ASCII.
' ' represents whitespace it's value in ASCII is 32.

Here is the updated code:-

#include<iostream>
#include<cstring>
#include<cctype>
using namespace std;

int main()
{
  string input;
  cout<<"Enter a sentence: ";
  getline(cin,input);
  int count[26] = {0},i,wordCount=0;
  for(i = 0; i< input.size();i++){
  if(((input[i]>='a' && input[i] <= 'z')||(input[i]>='A' && input[i] <= 'Z'))&&(input[i+1]=='.'||input[i+1]
  ==','||input[i+1]==' '))
  wordCount++;
  if(input[i]>='a' && input[i] <= 'z')
  count[input[i]-'a']++;
  if(input[i]>='A' && input[i] <= 'Z')
  count[input[i]-'A']++;


  }
  char x = input[input.size()-1];
  if(x != '.' && x != 'z' && x!= ' ')
  wordCount++;
  cout<<endl<<wordCount<<" words "<<endl;
  for(i=0; i<26; i++)
  {
    if(count[i]>0)
    cout<<count[i]<<" "<<(char)('a'+i)<<endl;
  }

}

Upvotes: 1

Related Questions