そんな使い方はいけませんfeof()
。fgets()
または同等のものを使用する必要があります。おそらくあまり知られていない (ただし標準の C89 には存在する) 変換指定子を使用する必要があります%n
。
#include <stdio.h>
int main(void)
{
char buffer[1024];
while (fgets(buffer, sizeof(buffer), stdin) != 0)
{
char *str = buffer;
char word[256];
int posn;
while (sscanf(str, "%255s%n", word, &posn) == 1)
{
printf("Word: <<%s>>\n", word);
str += posn;
}
}
return(0);
}
これは行を読み取り、sscanf()
繰り返し使用して行から単語をフェッチします。フォーマット指定子は%n
成功した変換にはカウントされないため、1 と比較します。 での%255s
オーバーフローを防ぐために を使用していることに注意してくださいword
。変換仕様で指定された 255 カウントの後に null を書き込む可能性があることにも注意してください。したがって、 の宣言と変換指定子sscanf()
の違いは 1です。char word[256];
%255s
明らかに、抽出された各単語をどう処理するかはユーザー次第です。ここのコードは単にそれを出力します。
に基づくソリューションに対するこの手法の利点の 1 つstrtok()
はsscanf()
、入力文字列を変更しないため、エラーを報告する必要がある場合に、元の入力行をエラー レポートで使用できることです。
質問を編集した後、セミコロンのような句読点は一言で言えば不要のようです。上記のコードには、単語の一部として句読点が含まれます。その場合は、どうすればよいか、もう少し考えなければなりません。開始点は、次の代わりに変換仕様として英数字スキャンセットを使用することです%255s
。
"%255[a-zA-Z_0-9]%n"
おそらく、次のコンポーネントの先頭にある文字を見て、英数字でない場合はスキップする必要があります。
if (!isalnum((unsigned char)*str))
{
if (sscanf(str, "%*[^a-zA-Z_0-9]%n", &posn) == 0)
str += posn;
}
につながる:
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char buffer[1024];
while (fgets(buffer, sizeof(buffer), stdin) != 0)
{
char *str = buffer;
char word[256];
int posn;
while (sscanf(str, "%255[a-zA-Z_0-9]%n", word, &posn) == 1)
{
printf("Word: <<%s>>\n", word);
str += posn;
if (!isalnum((unsigned char)*str))
{
if (sscanf(str, "%*[^a-zA-Z_0-9]%n", &posn) == 0)
str += posn;
}
}
}
return(0);
}
選択した英数字範囲の I18N および L10N の側面を考慮する必要があります。何が利用できるかは、実装によって異なります (POSIX では、残念ながらscanf()
などの表記のスキャン セットでのサポートを指定していません)。[[:alnum:]]