これは簡単な提案です。もっと良い方法があるかもしれませんが、私はこれが気に入っています。
まず、単語が何でできているかを「知る」ようにしてください。文字だけでできているとしましょう。句読点または「空白」である残りのすべては、セパレーターと見なすことができます。
次に、「システム」には2つの状態があります。1)単語の完成、2)セパレータのスキップです。
スキップ区切りコードのフリーランでコードを開始します。次に、次のセパレーターまたは文字列全体の終わりまで保持される「単語の完成」状態に入ります (この場合は終了します)。これが発生すると、単語が完成したので、単語カウンターを 1 増やし、「区切りをスキップする」状態になります。そしてループは続く。
疑似 C ライク コード:
char *str;
/* someone will assign str correctly */
word_count = 0;
state = SKIPPING;
for(c = *str; *str != '\0'; str++)
{
    if (state == SKIPPING && can_be_part_of_a_word(c)) {
        state = CONSUMING;
        /* if you need to accumulate the letters, 
           here you have to push c somewhere */
    }
    else if (state == SKIPPING) continue; // unneeded - just to show the logic
    else if (state == CONSUMING && can_be_part_of_a_word(c)) {
        /* continue accumulating pushing c somewhere 
           or, if you don't need, ... else if kept as placeholder */
    }
    else if (state == CONSUMING) {
        /* separator found while consuming a word: 
           the word ended. If you accumulated chars, you can ship
           them out as "the word" */
        word_count++;
        state = SKIPPING;
    }
}
// if the state on exit is CONSUMING you need to increment word_count:
// you can rearrange things to avoid this when the loop ends, 
// if you don't like it
if (state == CONSUMING) { word_count++; /* plus ship out last word */ }
関数 can_be_part_of_a_word は、たとえば、読み取った文字が [A-Za-z_] にある場合は true を返し、そうでない場合は false を返します。
(疲労の軽減に重大な誤りを犯していなければ、うまくいくはずです)