C言語関係掲示板

過去ログ

No730 英単語の頻度を数えるプログラム

[戻る] [ホームページ]
No.8943

英単語の頻度を数えるプログラム
投稿者---gon(2003/08/15 20:18:22)


英単語の頻度を数えるプログラムの簡易版を作成したのですが、14行目にエラーがあるらしく、以下のようなコメントが出ます。

14:two or more data types in declaration of 'main'

14行目というとint main() のところだと思うのですが、どこが間違っているのか見当が付きません。アドバイスをいただけるとありがたいです。

アルゴリズムは、単語の文字列と頻度を格納できる構造体の配列を用意して、
ファイルから1個単語を読み込んではその配列を最初から探索し、
一致した文字列があれば頻度を1増やし、なければ新たに単語をその配列に登録します。
単語を全部読み終わったら、最後にその配列を順番に出力すれば完成です。

I'mがIとmに分けられてしまう。andとAndが別の単語として認識されてしまう等、問題山積みのプログラムなのですが、とりあえず動作させてみてそれから改良を加えていこうと思っています。この手のプログラムを作成するにあたってのアドバイスもありましたら、よろしくお願いします。


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FILENAME  "file.txt"
#define SEPARATER " -,.?()'"
#define TABLESIZE 1000

struct word_count {
  char *word;
  int count;
}

int main() {
  FILE *fp;
  struct word_count word_table[TABLESIZE];
  char line[256], *token;
  int i, table_size;
  table_size = 0;

  if ((fp = fopen(FILENAME, "r")) == NULL) {
    printf("file open error!!\n");
    exit(1);
  }

  while(fgets(line, 256, fp) != NULL) {
    token = strtok(line, SEPARATER);
    for (i = 0; i < table_size; i++) {
      if (strcmp(token, word_table[i].word) == 0) {
        word_table[i].count++;
      } else {
        word_table[table_size].word = token;
        word_table[table_size].count = 0;
        table_size++;
      }
    }
      
    while (token != NULL) {
      token = strtok(NULL, SEPARATER);
      if (token != NULL) {
        for (i = 0; i < table_size; i++) {
          if (strcmp(token, word_table[i].word) == 0) {
            word_table[i].count++;
          } else {
            word_table[table_size].word = token;
            word_table[table_size].count = 0;
            table_size++;
          }
        }
      }
    }
  }

  fclose(fp);

  for (i = 0; i < table_size; i++) {
    printf("word=%s count=%d", word_table[i].word, word_table[i].count);
  }
  
  return(0);
}




No.8944

Re:英単語の頻度を数えるプログラム
投稿者---なお(2003/08/15 20:38:01)


structの宣言が;で終わっていない為じゃないでしょうか。

No.8945

Re:英単語の頻度を数えるプログラム
投稿者---gon(2003/08/15 20:43:53)


あっ!!ありがとうございました。(笑)

エラーは一応解決いたしましたが、この手のプログラムを作成するにおいて、アドバイスをしていただける方は引き続きよろしくお願いいたします。



No.8946

Re:英単語の頻度を数えるプログラム
投稿者---なお(2003/08/15 20:55:02)


andとAndが別の文字として認識されてしまうのは、一文字読み取るたびに
tolower()等で、全部小文字(大文字)に変えてしまえば防げます。

No.8948

大文字から小文字へのアドバイスありがとうございました。
投稿者---gon(2003/08/15 20:56:26)



大文字から小文字へのアドバイスありがとうございました。
感謝いたします。

No.8947

正常に動作しません
投稿者---gon(2003/08/15 20:55:10)


エラーは解決しましたが、実行してみるとまったく反応なしですね。
しゅ。。出力がない(汗)。。



No.8949

Re:正常に動作しません
投稿者---なお(2003/08/15 20:59:27)


for (i = 0; i < table_size; i++)の部分が問題だと思います。
table_sizeは0で初期化されているので、このループに入る事はありません。


No.8953

とりあえず動くところまではいきましたが。。動作がおかしいです。
投稿者---gon(2003/08/16 05:37:33)


改めてご指摘の所も含めて書き直してみました。
しかし、this is a pen.と書かれたtest.txtで試しに実行してみると、実行結果が以下の様になり、うまくいきません。アドバイスをいただけるとありがたいです。よろしくお願いします。

word=
count=2
word= is count=1
word= a count=1
word= pen count=1
word=
count=1

thisが表示されてくれないのです。プログラム中にprintfを挿入してどこでthisが消えてしまうのかを探してみましたが、特定ができません。
28行目のtokenではきちんとthisが切り出されているようですし、
53行目あたりでword_table[0].wordを一旦出力してみても、きちんと格納されているようなのですが、最後に出力されるまでになくなってしまうようです。


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FILENAME  "test.txt"  /*入力するファイル名*/
#define SEPARATOR " -,.?()'"  /*単語を区切る文字*/
#define TABLESIZE 1000        /*word_tableの大きさ*/

struct word_count {
  char *word;  /*単語*/
  int count;   /*頻度*/
};

int main() {
  FILE *fp;
  struct word_count word_table[TABLESIZE]; /*単語と頻度を格納する配列*/
  char line[256], *token;
  int i, table_size, find;
  table_size = 0;

  /*ファイル入力にエラーが生じた場合*/
  if ((fp = fopen(FILENAME, "r")) == NULL) {
    printf("file open error!!\n");
    exit(1);
  }

  while(fgets(line, 256, fp) != NULL) {
    token = strtok(line, SEPARATOR);
	find = 0;
	if (table_size == 0) {
		word_table[table_size].word = token;
		word_table[table_size].count = 1;
		table_size++;
	} else {
		/*word_tableとの照合*/
		for (i = 0; i < table_size; i++) { 
			/*一致する単語を見つけた場合*/
			if (strcmp(token, word_table[i].word) == 0) {
				word_table[i].count++;  /*その単語のカンウントを1増やす*/            
				find = 1;  /*word_table中に一致する単語があった!*/
				break;
			} 
		}

		/*word_table中に一致する単語がなかった場合*/
		if (find == 0) { 
			/*word_tableの最後尾に単語を登録する*/
			word_table[table_size].word = token;
			word_table[table_size].count = 1;
			table_size++;      
		}
	}

	while (token != NULL) {
		token = strtok(NULL, SEPARATOR);
		find = 0;
		if (token != NULL) {
			/*word_tableとの照合*/
			for (i = 0; i < table_size; i++) {
				/*一致する単語を見つけた場合*/
				if (strcmp(token, word_table[i].word) == 0) {
					word_table[i].count++;
					find = 1;
					break;
				} 
			}

			/*word_table中に一致する単語がなかった場合*/
			if (find == 0) {
				word_table[table_size].word = token;
				word_table[table_size].count = 1;
				table_size++;       
			}	
		}
	}
  }
  fclose(fp);

  /*word_tableを出力*/
  for (i = 0; i < table_size; i++) {
    printf("word=%5s count=%d\n", word_table[i].word, word_table[i].count);
  }
  
  return(0);
}




No.8954

Re:とりあえず動くところまではいきましたが。。動作がおかしいです。
投稿者---あかま(2003/08/16 10:09:07)


構造体のwordがポインタで、
token = strtok(line, SEPARATOR);
word_table[table_size].word = token;
とすると、一見うまくいっているように見えますが、
二回目以降のfgetsでlineの内容が書き換わってしまうので問題です。
この部分は動的にメモリを確保し、strcpyで書き写してやる必要があります。

それ以外は一通りOKかと。
ただプログラムがかなり冗長です。
同じコードが複数出てきた場合は、ループの書き方を改善するとコードを減らせることが多いです。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FILENAME  "test.txt"  /*入力するファイル名*/
#define SEPARATOR " -,.?()'"  /*単語を区切る文字*/
#define TABLESIZE 1000        /*word_tableの大きさ*/

struct word_count {
  char *word;  /*単語*/
  int count;   /*頻度*/
};

int main() {
  FILE *fp;
  struct word_count word_table[TABLESIZE]; /*単語と頻度を格納する配列*/
  char line[256], *token;
  int i, table_size, find;
  table_size = 0;

  /*ファイル入力にエラーが生じた場合*/
  if ((fp = fopen(FILENAME, "r")) == NULL) {
    printf("file open error!!\n");
    exit(1);
  }

  while(fgets(line, 256, fp) != NULL) {
  	token = strtok(line, SEPARATOR);
	for(;token!= NULL;token = strtok(NULL, SEPARATOR)){
		find = 0;
		/*word_tableとの照合*/
		for (i = 0; i < table_size; i++) {
			/*一致する単語を見つけた場合*/
			if (strcmp(token, word_table[i].word) == 0) {
				word_table[i].count++;
				find = 1;
				break;
			} 
		}

		/*word_table中に一致する単語がなかった場合*/
		if (find == 0) {
			word_table[table_size].word = malloc((strlen(token)+1)*sizeof(char));
			strcpy(word_table[table_size].word,token);
			word_table[table_size].count = 1;
			table_size++;       
		}
	}
  }
  fclose(fp);

  /*word_tableを出力*/
  for (i = 0; i < table_size; i++) {
    printf("word=%5s count=%d\n", word_table[i].word, word_table[i].count);
  }
  
  return(0);
}


No.8961

Re:とりあえず動くところまではいきましたが。。動作がおかしいです。
投稿者---gon(2003/08/17 07:59:13)


>同じコードが複数出てきた場合は、ループの書き方を改善するとコードを減らせることが多いです。

というのは、大変参考になりました。

>for(;token!= NULL;token = strtok(NULL, SEPARATOR))

というのも、目から鱗でした。。forループをこんな風に使っているのを見たことがなかったもので。。汗

どうもありがとうございました。