Example:

There are literally hundreds of programming languages.

The number of nonblank characters is : 48

So far i have come up with:

for (cin.get(inputLetter); inputLetter != '\n'; cin.get(inputLetter))
{
if ((inputLetter >= 'A' || 'a') && (inputLetter <= 'Z' || 'z'))
numUpper++;


}

Dani AI

Generated

The example in the original post is ambiguous: do you want to count every character, every nonblank (space) character, every non-whitespace character (spaces, tabs, etc.), or only alphabetic/uppercase letters? showed an example with "nonblank" — clarify which definition you mean before choosing an approach.

A simple, robust approach for a single input line is to read the whole line and count characters that are not classified as whitespace. The standard functions work fine for this as long as you cast char to unsigned char before calling the classification functions (this avoids UB on platforms where char is signed). See std::getline and std::isspace for details.

Example (reads one line and counts non-whitespace):

#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>

int main() {
  std::string line;
  if (!std::getline(std::cin, line)) return 0;
  auto nonws = std::count_if(line.begin(), line.end(), [](unsigned char c){
    return !std::isspace(c);
  });
  std::cout << "Non-whitespace characters: " << nonws << '\n';
}

If you need counts of alphabetic/upper/lower, extend the predicate with std::isalpha/std::isupper (again cast to unsigned char). That follows the same idea mentioned by and avoids the operator mistakes in the original test that pointed out. For interactive or multi-line input, loop on std::getline until EOF (this handles \n cleanly); and ’s stream/EOF notes are relevant there.

Caveat: std::string::size() reports bytes, not Unicode code points. If input may be UTF-8 and you need user-perceived characters, use a UTF-8 aware library (ICU, utf8cpp) or formally decode code points rather than relying on size(). See the Unicode site for background: unicode.org.

Recommended Answers

All 6 Replies

well, you may try using FOR Loops!!

den Counter++;

>>if ((inputLetter >= 'A' || 'a') && (inputLetter <= 'Z' || 'z'))

You can't use the || operator like that. Here is how you have to do that if ((inputLetter >= 'A' && inputLetter <= 'Z') || (inputLetter >='a' && inputLetter <='z')) A better way is to convert the letter to upper case (or lower case) then do just one comparison

inputLetter = toupper(inputLetter);
if( toupper(inputLetter) )
{
   // blabla
}

Edward is confused. The topic asks a different question than the example output suggests, and the example code doesn't solve the same problem as the example output suggests. :confused: Are you counting all characters, all non-blank characters, all upper case characters, or something else entirely?

Anyway, since the problem seems to be one of character classification, it's better to solve it directly using the standard library instead of doing it manually or indirectly:

#include <cctype>
#include <iostream>

int main()
{
  using namespace std;

  int upper = 0;
  int lower = 0;
  int alpha = 0;
  char ch;

  while (cin.get(ch)) {
    if (isalpha(ch)) {
      ++alpha;

      if (isupper(ch))
        ++upper;
      else if (islower(ch))
        ++lower;
    }
  }

  cout << "Alpha: " << alpha << '\n'
    << "Upper: " << upper << '\n'
    << "Lower: " << lower << '\n';
}

This can be extended for just about any basic test you might need using the standard C .

The character class functions are better because they'll still work for other languages where the classification rules might be different, but the manual test only works for english and languages with the same casing rules.

// Always true!
if( toupper(inputLetter) )
{
   // blabla
}

toupper() returns the converted character or the unconverted character if there's no upper case equivalent. Unless inputLetter has a value of 0, that if statement will always be true. Ed's guess is that this is a typo and you meant isupper() instead of toupper(). :)

Never forget to test end of stream condition (avoid loop forever):

const int eof = char_traits<int>::eof();
    int ch, n;
    for (;;)
    {
        cout << ">"; cout.flush();
        for (n = 0; (ch=cin.get()) != eof && ch != '\n'; ++n)
        {
            // process ch as you wish
        }
        if (!cin)
            break;
        cout << n << " chars" << endl;
    }
// Not needed if the right overload of cin.get() is used
const int eof = char_traits<int>::eof();
int ch, n;

// Infinite loops feel kudgy; maybe a do loop instead?
for (;;)
{
    // flush() isn't needed here
    cout << ">"; cout.flush();

    // istream& get(char&) wouldn't be as verbose
    for (n = 0; (ch=cin.get()) != eof && ch != '\n'; ++n)
    {
        // process ch as you wish
    }
    if (!cin)
        break;
    cout << n << " chars" << endl;
}

The first flush isn't needed because the next operation is to read a character with cin.get(). cin is tied to cout, and that means every extraction from cin will automatically flush cout first.

That whole char_traits<> thing is a lot of work and extra code just to test for eof. Why not use the overload of cin.get() that returns the stream object and let the void* conversion do the work for you? :)

do {
  cout << ">";

  char ch;
  int n;

  for (n = 0; cin.get(ch) && ch != '\n'; ++n) {
    // process ch as you wish
  }

  if (!cin.eof())
    cout << n << " chars" << endl;
} while (cin.good());

It's a good practice to limit the scope of variables as much as possible, so Ed moved ch and n inside the loop. Also, a do loop flows better than an infinite loop for this solution, I think. :)

cin.get(ch) is better than (ch=cin.get()), I agree.

About for and do loops: I think, it's one of well-known loop patterns:

loop
   prepare the step...
        if nothing to do then break
   do the real work
end loop

In this case:

loop
     try to count user input
          if nothing to do (eof occured) then break
     print counter
loop again

That's just what a reader expects after for (;;) line.
do-while loop corresponds to another pattern:

loop
     do the step unconditionally    
loop until all done

So I don't like two absolutely identical condition checks in do-while variant presented above.

Of course, tastes differ.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.