分割した単語の頻出頻度表示プログラムの作成とアドバイスの求め方

このQ&Aのポイント
  • 英文テキストファイルを読み込み、分割した単語の頻出頻度を表示するプログラムを作成しています。
  • 現時点では、分割した単語の表示しかできていません。
  • どなたか良きアドバイスをお願いします。
回答を見る
  • ベストアンサー

分割した単語の頻出頻度を表示させたい

英文テキストファイルを読み込み、分割した単語の頻出頻度を表示するプログラムを作成しています。 現時点では、分割した単語の表示しかできていません。 どなたか良きアドバイスをお願いします。 #include <stdio.h> int main() { int i,key,len,num ; int sp=0; char str[100000],*ptr[100000] ; FILE *fp; if ((fp=fopen("test.txt","r"))==NULL) { return -1; } num = 0 ; len = 0 ; ptr[0] = str ; do { key = fgetc(fp); str[len] = (char)key ; if ( (key==' ' && sp==0) || key == '.' || key == ',' || key == '!' || key == '?' || key == '"' || key == 0x0a || key == 0x0d ){ str[len] = '\0' ; if ( str+len-ptr[num] ){ num ++ ; } ptr[num] = str+len+1 ; if( key==',' || key=='.' || key== '!' || key=='?' || key=='"'){ str[++len]=(char)key; str[++len]='\0'; ptr[++num]=&str[len+1]; } } sp= (key== ' ')?1:0; len ++ ; } while ( key != EOF && len < 255 ); str[255] = '\0' ; for (i=0 ;i<num ;i++){ printf("%s\n",ptr[i]); } fclose(fp); return i; }

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

まず頻度用の表を作っておき、分割した単語を登録するときに、登録済みの単語と比較して同じものがあれば該当の頻度を+1、なければ単語を登録して該当の頻度を1にセットすればいいように思います。 参考まで。(単語切り出しの仕様がいまいち分かってません) #include <stdio.h> #include <stdlib.h> #include <string.h> #define WORD_MAX 1000 /* 単語帳の登録数 */ #define WORD_SIZE 100 /* 単語の最大長 */ char *word[WORD_MAX]; /* 単語帳 */ int freq[WORD_MAX]; /* 頻度表 */ int wordp=0; /* 単語帳の最後 */ /******************************************/ /* 単語登録(すでに登録済みなら頻度+1) */ /******************************************/ void add_word(char *s) {  int i;  if (strlen(s)==0) return; /* 長さ0は登録しない */  for (i=0; i<wordp; i++) { /* 登録済みかどうか調べる */   if (strcmp(word[i],s)==0) {    freq[i]++;    break;   }  }  if (i==wordp) { /* 登録されてなければ追加する */   if ((word[wordp]=malloc(strlen(s)))==NULL) exit(1);   strcpy(word[wordp],s);   freq[wordp]=1;   if (wordp<WORD_MAX-1) wordp++;  } } /******************************/ /* ファイルから単語を切り出す */ /******************************/ void split_word(FILE *fp) {  char buf[WORD_SIZE];  int bufp=0;  int key;  int sp=0; /* 空白チェック用フラグ */  while((key=fgetc(fp))!=EOF) {   if (key==' ' && sp==0) { /* 空白の1個目は単語区切り文字とする */    buf[bufp]='\0'; bufp=0; add_word(buf); sp=1;   } else {    if( key=='.' || key== '!' || key=='?' || key=='"'){ /* 特定の区切り文字は単語登録する */     if (sp==1) { /* 空白に続く場合は空白含めて登録する */      buf[bufp]=key; if (bufp<WORD_SIZE-1) bufp++;      buf[bufp]='\0'; bufp=0; add_word(buf); sp=0;     } else {      buf[bufp]='\0'; bufp=0; add_word(buf);      buf[0]=key; buf[1]='\0'; add_word(buf);     }    } else {     if (key == ',' || key == 0x0a || key == 0x0d ){ /* 普通の区切り文字 */      buf[bufp]='\0'; bufp=0; add_word(buf); sp=0;     } else { /* 区切り文字ではない文字(空白の2個目以降は区切り文字としない) */      buf[bufp]=key; if (bufp<WORD_SIZE-1) bufp++;      if (key != ' ') sp=0;     }    }   }  }  if (bufp>0) { /* 単語直後にEOFがきた場合 */   buf[bufp]='\0'; add_word(buf);  } } /******************/ /* 単語を表示する */ /******************/ void print_word(void) {  int i;  for (i=0; i<wordp; i++) {   printf("%d [%s] %d\n",i,word[i],freq[i]);  } } /************************************/ /* 単語用に確保したメモリを解放する */ /************************************/ void free_word(void) {  int i;  for (i=0; i<wordp; i++) {   free(word[i]);  } } /**********/ /* メイン */ /**********/ int main(int argc, char **argv) {  FILE *fp;  if (argc!=2) return -1; /* コマンドラインでファイル名指定 */  if ((fp=fopen(argv[1],"r"))==NULL) return -1; /* ファイル開けない */  split_word(fp); fclose(fp); /* 単語切り出し */  print_word(); /* 単語表示 */  free_word(); /* メモリ解放 */  return 0; }

yosudesu
質問者

補足

具体例を出していただき有難うございます。 プログラムを実行したところ23行目 if ((word[wordp]=malloc(strlen(s)))==NULL) exit(1);がエラーだったので if ((word[wordp]=(char*)malloc(strlen(s)))==NULL) exit(1);としたところ、エラーは0になりましたが実行すると "Press any key to continue"と表示され、ファイルを読み込むことができません。 自分なりに試行錯誤してみましたがどうも上手くいきません。何か特別な実行方法があるのでしょうか。

その他の回答 (1)

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.1

とりあえず、いまあるプログラムは捨てて新しく作りましょう♪ 空白文字(スペースやタブ)ピリオドやカンマ、感嘆符、疑問符などで単語を切り出すプログラムを作りましょう。 切り出した文字を登録する「辞書(頻度が記録できる)」を実現するプログラムを作りましょう。 とりあえずの辞書ができたら、検索、更新、登録なんかが素早くできるように、ブラッシュアップしましょう。 プログラムの練習でそういうのを作っているのでないなら、Perlなどを使うのが吉

yosudesu
質問者

お礼

うーん。1から作り直すとなると難しいですね

関連するQ&A

  • このプログラムを改良したい

    この単語分割プログラムを区切り文字である( . ? ! " )等も一つの単語として表示させたいのですが、どう改良したらいいかわかりません。 どなたかプログラムの追加削除を教えていたたけないでしょうか。 #include <stdio.h> int main() { int i,key,len,num ; char str[256],*ptr[128] ; num = 0 ; len = 0 ; ptr[0] = str ; do { key = getchar(); str[len] = (char)key ; if ( key == ' ' || key == '.' || key == ',' || key == '!' || key == '?' || key == '"' || key == 0x0a || key == 0x0d ){ str[len] = '\0' ; if ( str+len-ptr[num] ){ num ++ ; } ptr[num] = str+len+1 ; } len ++ ; } while ( key != 0x0a && key != 0x0d && len < 255 ); str[255] = '\0' ; for (i=0 ;i<num ;i++){ printf("%d. %s\n",i+1,ptr[i]); } return i ; } *教えてgoo 質 問 No.919881 arukamunさんのプログラムを引用しました。

  • テキストファイルから読み込ませたい

    このプログラムをテキストファイルから読み込ませたいのですが、 どう改良したらいいかわかりません。どなたかプログラムの追加を教えていたたけないでしょうか。 #include <stdio.h> int main() { int i,key,len,num ; char str[256],*ptr[128] ; num = 0 ; len = 0 ; ptr[0] = str ; do { key = getchar(); str[len] = (char)key ; if ( key == ' ' || key == '.' || key == ',' || key == '!' || key == '?' || key == '"' || key == 0x0a || key == 0x0d ){ str[len] = '\0' ; if ( str+len-ptr[num] ){ num ++ ; } ptr[num] = str+len+1 ; if( key=='.' || key== '!' || key=='?' || key=='"'){ str[++len]=(char)key; str[++len]='\0'; ptr[++num]=&str[len+1]; } } len ++ ; } while ( key != 0x0a && key != 0x0d && len < 255 ); str[255] = '\0' ; for (i=0 ;i<num ;i++){ printf("%d. %s\n",i+1,ptr[i]); } return i ; }

  • プログラムの改良

    文章を単語毎に分割するプログラムを作っています。 下記のプログラムだと I□am□a□boy. の場合、Iとamとaとboyと.に分割され、ここまではいいのですが。 さらにI□am□□a□□□boy□.とスペースが余計に入ってしまってる文章の場合に、Iとamと□aと□□boyと□. と表示させたいのですがどう改良したらいいのか分かりません。 下記のプログラムだとI□am□□a□□□boy□.はIとamとaとboyと.になってしまいます。 どなたかプログラムの追加を教えていただけないでしょうか。□はスペース一個を表しております。 #include <stdio.h> int main() { int i,key,len,num ; char str[256],*ptr[128] ; num = 0 ; len = 0 ; ptr[0] = str ; do { key = getchar(); str[len] = (char)key ; if ( key == ' ' || key == '.' || key == ',' || key == '!' || key == '?' || key == '"' || key == 0x0a || key == 0x0d ){ str[len] = '\0' ; if ( str+len-ptr[num] ){ num ++ ; } ptr[num] = str+len+1 ; if( key=='.' || key== '!' || key=='?' || key=='"'){ str[++len]=(char)key; str[++len]='\0'; ptr[++num]=&str[len+1]; } } len ++ ; } while ( key != 0x0a && key != 0x0d && len < 255 ); str[255] = '\0' ; for (i=0 ;i<num ;i++){ printf("%d. %s\n",i+1,ptr[i]); } return i ; }

  • _popen() のエラー取得

    WindowsNT/2000で_popen()を利用してコマンドを実行しているのですが、その際のメッセージを取得したいのですが、通常のメッセージは取得出来るのですが、エラーメッセージが取得出来ません。どうすればよいのでしょうか? 現在のソースは下記のようです。 int main(int argc, char* argv[]) { char str[512],*ptr; FILE *fp; if((fp = _popen("dir b:","rt")) == NULL) { fprintf( stderr , "error!!!\n"); return -1; } while(1) { fgets(str,512,fp); if(feof(fp)) { break; } ptr = strchr(str,'\n'); if(ptr != NULL) { *ptr='\0'; } printf("%s\n",str); } _pclose(fp); return 0; }

  • C言語、fgetcを利用しファイルの内容を変数に

    C言語について質問です C言語のfgetcを利用しファイルの内容を変数にいれてそれを返す関数を作っているのですがうまくいきません <!--以下ソース--> char *file_get_contents(char *filename){ FILE *fp; int c; char *return_str; if((fp=fopen(filename,"r"))==NULL) return NULL; while((c=fgetc(fp))!=EOF ){ sprintf(return_str,"%c",c); } fclose(fp); return return_str; } 誰か理由と改善方法を教えてください!

  • 文字列の扱い方

    初歩的な質問ですみません… str文字列からcという文字を見つけたら添字を返すという関数を作ったのですが、 iにこの関数を代入して、if文の制御式にiを使って比較するまでは正常なのですが、 真文にiを使うと何故か偽文(という言い方でいいのでしょうか…この場合("そんな値はありません。"というところです)が実行されてしまいます。 よろしければご教授お願い致します。 #include <stdio.h> int str_char(const char str[],int c) { int len = strlen(str); int i; for (i = 0;i < len;i++) { if (str[i] == c) return i; } return -1; } int main() { char str[64] = "Fucking Brutal Death Metal"; int ch,i; printf("どの文字を調べますか?"); scanf("%c",&ch); i = str_char(str,ch); if (i >= 0) printf("その文字は%d番目にあります。",str_char(str,ch) + 1); //何故かiだと動かない else printf("そんな値はありません。"); return 0; }

  • ユニコード文字列の分割

    csvやファイルパスをカンマや'\'で分割する関数をユニコードでも 対応できるように改修していのですがやり方が分かりません。 関数のロジックはおおよそ以下の通りです。 (仕事先のセキュリティの関係でソースは持ち出せませんので概要ですが・・・) split(str, item, len, words[item][len], delimiter) char* str: 分割対象の文字列 int item:項目数(上限あり) int len:項目の文字数(上限あり) words[item][len]:文字列を分割、項目として格納する配列 char delimiter:区切り文字 int i=0, j=0; while(*str != NULL){ // 文字列を分割する処理 if(str != delimiter){ words[i][j++] = *str } else if{ words[i][j] = NULL i++; j=0; } ・・・・・・・・・ str++; } // 後処理があります VCの設定がマルチバイト対応だったので問題なかったのですが ユニコードに設定を切り替えるとパスの分割でカタカナの「ソ」 を含む文字列が正しく分割されないという事象が発生しました。 関数内の改修だけで解決する方法があるでしょうか? ある程度プロジェクトが動いているのであまり時間をかけないで 対応する必要があります。 OS: Windows7 SP1 環境: VC++ 2008 MFC

  • C言語で、ファイルを読み込んで数字と名前に分けて配列に格納に関する質問

    C言語で、ファイルを読み込んで数字と名前に分けて配列に格納に関する質問です! ファイルを開いた後でエラーとなるのですが、何が足りないのでしょうか? ファイル内容 20 田中 10 鈴木 #include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc,char *argv[]) { FILE *fp; char str[256]; char *tp; int k,i=0; int num[10]; char na[10][20]; fp=fopen(argv[1],"r"); if(fp==NULL){ printf("ファイルを開けません\n"); return 1; }else{ printf("開けた\n"); } while(fgets(str,sizeof str,fp)!=NULL){ tp=strtok(str," "); num[i]=atoi(tp); tp=strtok(NULL," "); strcpy(na[i],tp); i++; } printf("%d\n%s\n",num[0],na[0]); printf("%d\n%s\n",num[1],na[1]); fclose(fp); return 0; }

  • C++のoperator関数でのキャストする場合の書き方がまだよく理解

    C++のoperator関数でのキャストする場合の書き方がまだよく理解できていません。 下記のコードで、 //ここから #include "stdafx.h" #include <string> #include <iostream> class AutoPtr { char *ptr; public: AutoPtr():ptr(0) { } ~AutoPtr() { delete [] ptr; } // char *operator=(char *ptr) { delete [] this->ptr; this->ptr = ptr; return this->ptr; } operator char *(){ return ptr; } char &operator[](int index) { return ptr[index]; } }; void reverse(char *str) { int i, n; AutoPtr work; n = strlen(str); work = new char[n+1]; strcpy(work, str); for(i=0; i<n; i++) { str[i] = work[n-i-1]; } printf("%s\n", str); } int _tmain(int argc, _TCHAR* argv[]) { char str[] = "ABCDEFG"; reverse(str); return 0; } //ここまで 2番目のoperator関数の定義ですが、 operator char *(){ return ptr; } これは多分、reverse()関数中の、 strcpy(work, str); のworkの展開に用いられると思うのですが、 機能としては、「operator char *」はAutoPtrをchar *にキャストするために使われているらしいのですが、何故この書き方でAutoPtrをchar *型にキャストできるのかがいまいち分かりません。また、2番目のoperator関数の記述「operator char *()」はどこまでが型で、どこからが関数の定義と見なせばよいのでしょうか? 何か勘違いしているかもしれません。理解されている方、御教示いただければと思っています。 よろしくお願い致します。

  • 教えてください

    入力した文字列のスペースをすべて取り除く関数を返すのですが、分かりません。(例)a s d fと入力したら、asdfと表示します。途中まで考えたのですが、どうしてもできません。教えてください。宜しくお願いします。(このソースは、コンパイルエラーです。) 14: 移植性のないポインタ変換(関数a) #include <stdio.h> char a(char *st) { char *ptr=st; while(*st!='\0') { if (*st != ' ') { *ptr++=*st; } } *ptr='\0'; return(ptr); } int main(void) { char str[21]={'\0'}; int i=0; char ch; printf("文字列を入力してください:"); while(i<21) { ch=getchar(); if (ch=='\n') {break; } else if (ch != '\0' && ch != '\n') { str[i] =ch; i++; } } str[i] = '\0'; printf("%s",a(str)); return(0); }