Counting the number of words in a string I have written this program to count the number of words in a string. I have checked my program for the worst-case scenario. If any of you can find any cases for which this program doesn't work, please let me know so that I can work and improve it.

And just to be clear, we don't want symbols like, "," , "!" , "?", "." , "\n" to be counted as words. But obviously, "I" should be counted as word, as we consider it in the language. I have made sure of all this by replacing them with spaces. Let me know if I have missed something. 

Is this a good solution?  How can I improve the code?

#include &lt;iostream&gt;
#include &lt;string&gt; 

void replace(std::string&amp; str, char x, char y);
int countWords(std::string x);

int main(){
std::cout&lt;&lt;countWords(" \n \t Hello, world ! ");
}

void replace(std::string&amp; const str, char x, char y){
for(unsigned int i=0;i&lt;str.size();i++){
    if(str[i]==x) str[i]=y;
}
}

int countWords(std::string x){

replace(x,',',' ');
replace(x,'.',' ');
replace(x,'!',' ');
replace(x,'?',' ');
replace(x,'(',' ');
replace(x,')',' ');
replace(x,'\n',' ');
replace(x,'\t',' ');
replace(x,'"',' ');

if(x.empty()) return 0;
int Num=1;

for(unsigned int i=1;i&lt;x.size();i++){
    if(x[i]==' ' &amp;&amp; x[i-1]!=' ') Num++;
}
if(x.back() == ' ') Num--;
return Num;
}
I personally would use the built-in way of reading words.

std::stringstream wordStream("A list of words");

std::string       word;
int               count = 0;
while(wordStream &gt;&gt; word)
{
    ++count;   // We read one space separated words
}              // from the stream.


Of course the default does not handle punctuation correctly (as the words are divided by space. But we can handle that.

So how do we make things look like a space.
All you need to do is tell the stream what characters are spaces. To do this you need to create a ctype facet and implant it into the stream.

#include &lt;locale&gt;
#include &lt;string&gt;
#include &lt;sstream&gt;
#include &lt;iostream&gt;

// This is my facet that will treat the ,.- as space characters and thus ignore them.
class WordSplitterFacet: public std::ctype&lt;char&gt;
{
    public:
        typedef std::ctype&lt;char&gt;    base;
        typedef base::char_type     char_type;

        WordSplitterFacet(std::locale const&amp; l)
            : base(table)
        {
            std::ctype&lt;char&gt; const&amp;  defaultCType  = std::use_facet&lt;std::ctype&lt;char&gt; &gt;(l);

            // Copy the default value from the provided locale
            static  char data[256];
            for(int loop = 0;loop &lt; 256;++loop) { data[loop] = loop;}
            defaultCType.is(data, data+256, table);

            // Modifications to default to include extra space types.
            table[',']  |= base::space;
            table['.']  |= base::space;
            table['!']  |= base::space;
            table['?']  |= base::space;
            table['(']  |= base::space;
            table[')']  |= base::space;
        }
    private:
        base::mask  table[256];
};


Now you just have to add it to a stream.

int main()
{
    std::stringstream   wordsAndPunt("word1 ,,, word2");
    wordsAndPunt.imbue(std::locale(std::locale(), new WordSplitterFacet(std::locale()));

    // Now apply the count.
    std::string word;
    int         count = 0;
    while(wordsAndPunt &gt;&gt; word)
    {
        ++count;   // We read one space separated words
    }              // from the stream.
    std::cout &lt;&lt; count &lt;&lt; "\n";
}


Now we have the basics in place you don't even need the loop. You can replace it with standard algorithms.

int main()
{
    std::stringstream   wordsAndPunt("word1 ,,, word2");
    wordsAndPunt.imbue(std::locale(std::locale(), new WordSplitterFacet(std::locale()));

    // Now apply the count.
    int  count = std::distance(std::istream_iterator&lt;std::string&gt;(wordsAndPunt),
                               std::istream_iterator&lt;std::string&gt;());
    std::cout &lt;&lt; count &lt;&lt; "\n";

}