コードの問題は、各ループで文字を消費することです。'\n' は for 文の単語をスキャンするループによって消費されるため、外側のループはそれを認識しません。
問題の可能な解決策は次のとおりです。
int sentences = 0;
int words = 0;
int characters = 0;
int in_word = 0; // state of our parser
int ch;
do
{
int end_word = 1; // consider a word wil end by default
ch = getch();
characters++; // count characters
switch (ch)
{
case '.':
sentences++; // any dot is considered end of a sentence and a word
break;
case ' ': // a space is the end of a word
break;
default:
in_word = 1; // any non-space non-dot char is considered part of a word
end_word = 0; // cancel word ending
}
// handle word termination
if (in_word and end_word)
{
in_word = 0;
words++;
}
} while (ch != '\n');
これらの構文解析の問題に対する一般的なアプローチは、一度に 1 文字を読み取り、この文字がトリガーできるすべての可能な遷移に反応する有限状態マシンを作成することです。
この例では、マシンは現在単語を解析しているかどうかを記憶する必要があるため、最初に終端のスペースまたはドットが検出された場合にのみ 1 つの新しい単語がカウントされます。
このコードでは、簡潔にするためにスイッチを使用しています。それを if...else if シーケンスに置き換えて、先生を喜ばせることができます :)。
先生が while ループのみを使用するように強制した場合、先生はばかげたことをしたことになります。他の条件式を含まない同等のコードは、より重く、理解しにくく、冗長になります。
一部の人々はそれが重要であると考えているように思われるため、考えられる解決策の 1 つを次に示します。
int sentences = 0;
int words = 0;
int characters = 0;
int in_word = 0; // state of our parser
int ch;
// read initial character
ch = getch();
// do it with only while loops
while (ch != '\n')
{
// count characters
characters++;
// count words
while (in_word)
{
in_word = 0;
words++;
}
// skip spaces
while (ch == ' ')
{
ch = -1;
}
// detect sentences
while (ch == '.')
{
sentences++;
ch = -1;
}
// detect words
while ((ch != '\n')
{
word_detected = 1;
ch = -1;
}
// read next character
ch = getch();
}
基本的に、人為的で不自然なプログラミング方法である に if (c== xxx) ...
置き換えることができます。while (c== xxx) { c = -1; ... }
運動は愚かなやり方を助長するべきではありません、私見です。
ですから、先生が尋ねたことをあなたが誤解したのではないかと思います。
明らかに、while
ループを使用できる場合は、if
ステートメントも使用できます。
ループだけでこの演習を行おうwhile
としても無駄であり、実際のパーサー コードとほとんどまたはまったく関係のない結果になります。