ファイルからデータを読み込んで、単語の出現頻度を調べるプログラムを作ろうと考えて、下記のようなプログラムを書いてみました。
#include <stdio.h>
#include <string.h>
main()
{ struct data
{char word[128];
int freq;}
word_data[128];
char words[128];
char term[128];
int i=0;
int nw=0;
int j;
char buff[128];
FILE *fp_in=fopen("data.txt","r");
while(fgets(fp_in,128,buff)!=EOF){
char buff[128];
int k;
for(k=0;k<=128;k++){
printf("%s",buff);
if(('A'<=buff[k] && buff[k]<='Z')||('a'<=buff[k] && buff[k]<='z'))
term[i++]=buff[k];
else if(i>0) term[i]='\0';}
for(j=0;j<nw;j++){
if(strcmp(term,word_data[j].word)==0) break;
if(j==nw)
{strcpy(word_data[j].word,term);
word_data[j].freq=1;
nw++;}
else if(j!=nw)
{word_data[j].freq++;
i=0;}
}}
for(j=0;j<nw;j++)
printf("%s %d",word_data[j].word,word_date[j].freq);
return 0;}
コンパイルは通ったのですが、実行しても画面に何も表示されません。原因は何処にあるのでしょうか?分かる方がいましたら、ご回答宜しくお願いします。
No.5ベストアンサー
- 回答日時:
各行に複数単語がある場合にも対応してみました。
一部エラーチェックのコードも追加しました。
-------------------------------------------------
#include <stdio.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
#define MAX_NWORDS 128
int isLetter(char c){
if( ('A'<=c && c<='Z') ||('a'<=c && c<='z') ) {
return TRUE;
}else{
return FALSE;
}
}
main() {
struct data {
char word[128];
int freq;
} word_data[MAX_NWORDS];
char term[128];
int nw=0;
int i,j,k;
char buff[128];
FILE *fp_in=fopen("data.txt","r");
while(fgets(buff,128,fp_in)!=NULL){
k=0;
while(buff[k]!='\n'){
while(! isLetter(buff[k]) && buff[k]!='\n') k++;
if(buff[k]=='\n')break;
i=0;
while(isLetter(buff[k])) term[i++]=buff[k++];
term[i]='\0';
for(j=0;j<nw;j++) if(strcmp(term,word_data[j].word)==0) break;
if(j==nw) {
strcpy(word_data[j].word,term);
word_data[j].freq=1;
nw++;
if(nw==MAX_NWORDS){
printf("more than %d words found.\n", MAX_NWORDS);
exit(1);
}
} else {
word_data[j].freq++;
}
}
}
for(j=0;j<nw;j++) printf("%s %d\n",word_data[j].word,word_data[j].freq);
return 0;
}
この回答への補足
丁寧にありがとうございます。
もう1点質問させていただきたいのですが、最終結果を出力するときに辞書式順序(A,a,B,b,・・,Z,z)にソートする場合はどうすればいいのでしょうか?昨晩自力でやってみたのですが、どうもうまくいきません。アスキーコードの配列を用いる気がするのですが、アスキーコードですと、'A'~'Z'の後に、'a'~'z'が続きますよね。これをそのまま用いると、大文字が先にまとめて表示されてしまい、小文字が後にまとめて表示されてしまいますよね。
また、'A'='a'-32ですので、一旦、全ての小文字を大文字に変換して、大小比較をし、また元に戻すといった手段も考えてみたのですが、私にはソースコードが書けませんでした。
宜しければ、ご回答お願いできますでしょうか?
以下に私が書いてみたソースコードを挙げておきます。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define MAX_NWORDS 128
int isLetter(char c){
if(('A'<=c && c<='Z')||('a'<=c && c<='z')){
return TRUE;
}else{
return FALSE;
}
}
main(){
struct data{
char word[128];
int freq;
};
struct data word_data[MAX_NWORDS];
struct data word_data_cp[MAX_NWORDS];
char term[128];
int nw=0;
int i,j,k,p,x;
char m;
char buff[128];
FILE *fp_in=fopen("data.txt","r");
while(fgets(buff,128,fp_in)!=NULL){
k=0;
while(buff[k]!='\n'){
while(!isLetter(buff[k]) && buff[k]!='\n') k++;
if(buff[k]=='\n')break;
i=0;
while(isLetter(buff[k])) term[i++]=buff[k++];
term[i]='\0';
for(j=0;j<nw;j++)
if(strcmp(term,word_data[j].word)==0) break;
if(j==nw){
strcpy(word_data[j].word,term);
word_data[j].freq=1;
nw++;
if(nw==MAX_NWORDS){
printf(" more than %d words found.\n",MAX_NWORDS);
exit(1);
}
}else{
word_data[j].freq++;
}}}
for(p=0;p<nw;p++){
for(j=0;j<nw-p-1;j++){
x=strcmp(word_data[j].word,word_data[j+1].word);
if(x>0){
word_data_cp[j]=word_data[j];
word_data[j]=word_data[j+1];
word_data[j+1]=word_data_cp[j];}
}}
for(j=0;j<nw;j++)
{printf("%s %d\n",word_data[j].word,word_data[j].freq);}
printf("Total %d Words\n",nw);
return 0;
}
No.7
- 回答日時:
修正版。
動作確認ずみ。strcmpを使っている部分は2箇所ありますが、
たぶん、2箇所めのstrcmpのみをこのstrcmp_dictorderに変更するのがよいと思います。
(大文字、小文字の違いによって意味が違う単語もありますので。)
int strcmp_dictorder(char*a,char*b){
int i;
char ca,cb;
for(i=0;i<=strlen(a);i++){
ca=a[i];if(ca>='a')ca-=32 ;
cb=b[i];if(cb>='a')cb-=32 ;
if(ca!=cb) return ca-cb;
}
for(i=0;i<=strlen(a);i++){
if (a[i]!=b[i]) return a[i]-b[i];
}
return 0;
}
何度も丁寧にありがとうございます。
先ほど、実行してみましたところ、小文字の後に大文字が続く個所が数箇所あったのですが、
最初のforループに
if(ca==cb-32) return 0;
if(ca-32==cb) return 1;
の2文を追加してみましたところ大文字→小文字の順番に上手く並びました。
文字列の比較では、strcmp関数を使うといったことしか
思い浮かばなかったので悩んでいたのですが、自分で関数を作ってしまえばいいのですね。また、教えて頂いた大文字と小文字を無視した大小関係の比較の書き方はなるほどと思いました。
お忙しいところ、丁寧に回答していただきまして本当にありがとうございました。これからも何か機会がありましたらよろしくお願いします。
No.6
- 回答日時:
以下のような関数を定義して、strcmpの代わりにつかってみてください。
返り値の符号は逆のほうがいいかもしれません。結果を見て適当に直してください。動作確認はしていません。
下の関数のa[i]でエラーがでるようなら、
a[i]を*(a+i)に変えてみてください。
int strcmp_dictorder(char*a,char*b){
int i;
char ca,cb;
for(i=0;i<=strlen(a);;i++){
ca=a[i];if(ca>='a')ca-=32
cb=b[i];if(cb>='a')cb-=32
if(ca<cb)return -1;
else if (ca>cb)return 1;
else if (a[i]<b[i])return -1;
else if (a[i]>b[i])return 1;
else ;/*compare next letter*/
}
return 0;
}
No.4
- 回答日時:
No3までを踏まえて動作するように書き換えてみました。
制御構造も一部かえました。回答No2に示したようなdata.txtに対して動作確認ずみです。-------------------------------------------------
#include <stdio.h>
#include <string.h>
main() {
struct data {
char word[128];
int freq;
} word_data[128];
char term[128];
int i;
int nw=0;
int j;
char buff[128];
FILE *fp_in=fopen("data.txt","r");
while(fgets(buff,128,fp_in)!=NULL){
int k;
i=0;
for(k=0;k<=128;k++){
if( ('A'<=buff[k] && buff[k]<='Z')||('a'<=buff[k] && buff[k]<='z') ) {
term[i++]=buff[k];
} else {
break;
}
}
if(i>0){
term[i]='\0';
for(j=0;j<nw;j++) if(strcmp(term,word_data[j].word)==0) break;
if(j==nw) {
strcpy(word_data[j].word,term);
word_data[j].freq=1;
nw++;
} else {
word_data[j].freq++;
}
}
}
for(j=0;j<nw;j++) printf("%s %d\n",word_data[j].word,word_data[j].freq);
return 0;
}
-------------------------------------------------
注意:上記ソースコードは、行頭に全角スペースが入っているため、そのままコピーペーストしてもコンパイルできないことがあります。
No.3
- 回答日時:
・char buffの宣言が2箇所にあります。
そのためファイルから読み込んだ文字列は、while文の内部で使われていません。・fgetsの書式が違います。
fgets(buff,128,fp_in,128,buff)のはずです。
・fgetsの返すファイル終端をあらわす値はEOFではなくNULLです。
・結果表示部で、word_dat"e"[j]を表示しようとしています。
・結果は、各単語の情報を表示するように改行も出力したほうがよさそうです。
・char words[128]は使われていません。
No.2
- 回答日時:
・各行のはじめの単語しかチェックしない仕様のようですが、それでいいのでしょか?
・行のはじめの1文字がA-Za-zのいずれかでない場合、term[0]の値が不定になります。この状態でstrcmpを実行すると問題がある気がします。
(上の2点は、各行が1単語からなり、その単語は行の1カラム目から始まる、という場合は問題ありませんが...)
・すでに登録した単語と同じ単語を見つけたばあい、iの値を0にリセットせずに次の行を読み込んでいます。次の行の単語は、term中の前回の単語の後ろに連結されます。
(
たとえば、データファイルが
and
and
or
だった場合、orを読み込んだ時点でのtermは、"andor"になります。(他の部分の動作に問題がなかったとしても)
)
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# c言語でユーザ関数を利用して入力された文字列を反転させるプログラムを作りたいです。 3 2023/01/29 19:47
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
fgetsなどのときのstdinのバッ...
-
C言語のfor文です。 繰り返しの...
-
charからLPTSTRへの変換方法
-
干支のプログラム
-
TCP/IP通信型大文字・小文字変...
-
文字列から空白を取り除きたい...
-
Visual Studio strcpyについて
-
charでの計算?
-
c++ 文字列を入力して、一文字...
-
構造体のアライメント調整
-
DPマッチング
-
Win32APIでのエディットボック...
-
sprintf関数の作り方
-
char型+char型ってint型? if...
-
CStringをwchar_tに変換したい
-
C言語のポインターで詰まっている
-
ランダムな英文字の文字列作成
-
c言語でユーザ関数を利用して入...
-
テキストデータをそのままバイ...
-
ネットワークにつながっている...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
fgetsなどのときのstdinのバッ...
-
charでの計算?
-
C言語のfor文です。 繰り返しの...
-
charからLPTSTRへの変換方法
-
文字列から空白を取り除きたい...
-
C言語の入力した文字を反転させ...
-
'const char *' 型は 'char *' ...
-
配列をnビットシフトする
-
str系関数を使わずに二つの文字...
-
int main()の・・・
-
atoi( ) の反対をやりたい
-
CStringをwchar_tに変換したい
-
c++ 文字列を入力して、一文字...
-
switch文で文字を比較すること...
-
干支のプログラム
-
3桁区切(コンマ)記号をつけ...
-
絶対パスからのファイル名の切...
-
間接操作のレベルとは
-
間接参照のレベルが異なっています
-
型変換
おすすめ情報