こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

締切り済みの質問

c言語で文書検索プログラムについて質問です。

いつもお世話になっています。
今回、大学の課題でc言語を用いて文書検索のプログラムを作成しています。

クエリ(検索単語)を2つ入力して、クエリ2つを同じ行に含む1文が存在した場合そのテキストファイルのファイル名を出力するプログラムを作成しています。

検索する文書は、ソースファイルと同じディレクトリにあるcorpusディレクトリ内のテキストファイルについて行います。

概ね、自力で作成はできているよう思うのですが、どうしても出力がうまくいきません。
出力条件、もしくはstrcmpのあたりに原因があるような気がするのですが・・・。
以降に私の作成したソースファイルを添付しておきますので、
原因のわかる方ぜひお願いします。


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

int main(int argc, char* argv[]){
FILE* fp;
char buffer[1024];
char kueri1[256];
char kueri2[256];
int flag_kueri = 0; //kueri1,kueri2がどちらもあれば1に
int flag_kueri1 = 0; //kueri1があれば1に
int flag_kueri2 = 0; //kueri2があれば1に
int i;
cahr* s;
char* delimiter = " .,";

/*コマンドラインが正しく入力されているかの確認*/
if(argc < 4){
printf("error1\n");
exit(1);
}

/*入力されたクエリ1をkueri1に格納*/
strcpy(kueri1,argv[1]);

/*入力されたクエリ2をkueri2に格納*/
strcpy(kueri2,argv[2]);

/*kueri1の英小文字を英大文字に変換する処理を\0まで繰り返す*/
s = kueri1;
while(*s != '\0'){
*s = toupper(*s);
s++;
}

/*kueri2の英小文字を英大文字に変換する処理を\0まで繰り返す*/
s = kueri2;
while(*s != '\0'){
*s = toupper(*s);
s++;
}

/*メインループ*/
for(i = 3; i < argc; i++){

/*ファイルを開く*/
if((fp = fopen(argv[i], "r")) == NULL){
printf("error2");
exit(1);
}

/*文書を1行ずつ読み込んで処理を行う*/
while(fgets(buffer,sizeof(buffer),fp) != NULL){

/*最後に\0を格納*/
buffer[strlen(buffer) - 1] = '\0';

/*bufferの英小文字を英大文字に変換する処理を\0まで繰り返す*/
s = buffer;
while(*s != '\0'){
*s = toupper(*s);
s++;
}

/*strtokを用いて単語ごとに区切っていく(1単語目)*/
s = strtok(buffer,delimiter);

if(s != NULL){

/*kueri1かどうか判定*/
if(strcmp(s,kueri1) == 0){
flag_kueri1 = 1;
}

/*kueri2かどうか判定*/
if(strcmp(s,kueri2) == 0){
flag_kueri2 = 1;
}

/*strtokを用いて単語ごとに区切っていく(1単語目)*/
while((s = strtok(NULL,delimiter)) != NULL){
/*kueri1かどうか判定*/
if(strcmp(s,kueri1) == 0){
flag_kueri1 = 1;
}

/*kueri2かどうか判定*/
if(strcmp(s,kueri2) == 0){
flag_kueri2 = 1;
}
}
}

/*kueriが両方なかったらflar_kueriを1にする*/
if(flag_kueri1 == 1 && flag_kueri2 == 1){

}else{
flag_kueri = 1;
}

/*両方のkueriがあればファイル名を出力*/
if(flag_kueri == 0){
s = argv[i];
printf("file_name: %s",s);
}
}

fclose(fp);

exit(0);

}

投稿日時 - 2012-07-26 17:45:56

QNo.7611961

すぐに回答ほしいです

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(4)

#2 です

判定は 関数fとできて 0または1を返せばよい

while文のなかで
 if (f(x) && f(y)) {
処理を行う
}


でかけてしまう。


オブジェクト指向言語で言われるリファクタリングの匂いはここでも有効です。重複行を避ける。
No3の方がいわれるのは、マジックナンバーを使うに近いかな。 それともう一点、一時的な変数を使わない。 フラグの変数を使わなくても 毎回関数を呼ぶ出せば、変数は使わなくてすむ。

なぜ変数を避けるかは、今の場合 毎回0に初期化されてないから、一度1を代入したら変更されない限り、1のまま。なぜなら、一番最初に定義されているので、while 文では同じスコープのまま!

つまり、一時的期変数はこういうミスが起きてしまうから、使うなっていうわけ。

投稿日時 - 2012-07-27 01:39:59

ANo.3

「出力がうまくいきません」ってのは, 具体的には何がどう「うまくいかない」んですか?

flag って名前はやめた方がいい. その「フラグ」が何を意味するのかを考え, その「意味」を表す名前を使うべき. 例えば query1_found みたいにすれば, コメントがなくても意味がわかるし, #1 で指摘されたような「矛盾」も起こしようがない.

投稿日時 - 2012-07-27 00:39:52

プログラムの書き方に問題がありませんか?

似たような行が多すぎる、ということは、流れが追いにくいということ。

人に聞くよりも、プリントデバッグの手法を学びましょう。

そのためにも、重複行を整理しないと。

何のための、構造型言語なのか? 

投稿日時 - 2012-07-26 18:44:24

補足

回答ありがとうございます。

要するに、同じような処理を繰り返すのであれば
重複した記述ではなく関数などを使って書いた方がいいということでしょうか?

投稿日時 - 2012-07-26 21:30:31

ANo.1

kueriはqueryの方がいいのではないか、というのはさておき…。

>int flag_kueri = 0; //kueri1,kueri2がどちらもあれば1に

>/*kueriが両方なかったらflar_kueriを1にする*/
>if(flag_kueri1 == 1 && flag_kueri2 == 1){

>}else{
>flag_kueri = 1;
>}

変数定義のところと実際の処理のところで、
flag_kueriの役割が矛盾しているように見えるのは気のせいでしょうか。

投稿日時 - 2012-07-26 18:01:22

補足

回答ありがとうございます。

確かにコメントアウトにミスがありました。
ご指摘ありがとうございます。

確かに、コメントアウトにミスはあったんですが処理自体は矛盾なく
両方、または片方のクエリが見つからなかった場合にはflag_kueriを1にすることで
ファイル名の処理を避けるようにしようと思っているのですが

if( flag_kueri1==1 && flag_kueri2==1){

}else{

flag_kueri=1;

}

とすることで、どちらか一方のクエリが見つからなかった場合はflag_kueriを1にする処理を行い、出力の際には

if(flag_kueri == 0){
s=argv[i];
printf("file name: %s\n);
}

とすることで、flag_kueri=0の時、つまりはどちらか一方、または両方のクエリが見つからなかったことによりflag_kueriを1にする処理は行われずファイル名が出力されるようになっていると思うのですが、いかがでしょうか?

投稿日時 - 2012-07-26 21:52:45

あなたにオススメの質問