4

次のようなテキストファイルがあるとします。

ユーザー:ジョン

デバイス:12345

日付:12/12/12

編集:

単語を正常に検索し、その単語の後に情報を表示するためのコードがあります。ただし、コードを編集して2つまたは3つの単語を検索し、1つの単語ではなくその後ろに情報を表示しようとすると、機能しません。同じwhileループにコードを追加し、別の単語の新しいwhileループを作成しようとしましたが、どちらも機能しません。私が間違っている/していないことがあるに違いありません。

アドバイスをお願いします、ありがとう!

これが私のコードです:

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 int main() {

char file[100];
char c[100];

printf ("Enter file name and directory:");
scanf ("%s",file);

    FILE * fs = fopen (file, "r") ;
    if ( fs == NULL )
    {
           puts ( "Cannot open source file" ) ;
           exit( 1 ) ;
    }

    FILE * ft = fopen ( "book5.txt", "w" ) ;
    if ( ft == NULL )
    {
           puts ( "Cannot open target file" ) ;
           exit( 1 ) ;
    }

while(!feof(fs)) {
   char *Data;
   char *Device;
   char const * rc = fgets(c, 99, fs);

   if(rc==NULL) { break; }

   if((Data = strstr(rc, "Date:"))!= NULL)
   printf(Data+5);

   if((Data = strstr(rc, "Device:"))!=NULL)
   printf(Device+6);
   }



    fclose ( fs ) ;
    fclose ( ft ) ;

return 0;

 }
4

8 に答える 8

1

私の提案は、freadを使用してすべてのファイルを読み取ることです。文字ごとに読み取ることもできますが、IMHO(ここでは個人的な好み)では、すべての文字を含む文字列を取得して操作する方が簡単です。

これは関数プロトタイプです:

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

読み取られた要素の数を返します。

例えば:

char buffer[100];
size_t n= fread(buffer, 1,100, fs);  

次に、文字列を操作してトークンに分割できます。

編集

ここには、文字列をトークンに分割する方法の例も記載された優れたリファレンスがあります。

http://www.cplusplus.com/reference/cstring/strtok/

于 2012-12-27T22:45:53.907 に答える
1

fgetcintにプロモートされた文字である整数値を返します。行全体を読み取ることを意味していると思いますfgetsが、そのためにメモリを予約する必要があります。たとえば、次のようになります。

#define BUF 100
...
char c[BUF];
fgets(c, BUF, fs);

いくつかの役立つ リンク

于 2012-12-27T22:46:43.307 に答える
1

コードにはいくつかの問題があります。基本的にはコンパイルされません。

これは、小さなクリーンアップを備えたバージョンです-少なくともコンパイルされます:

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

int main() {
    char file[100];
    char c[100];

    printf ("Enter file name and directory:");
    scanf ("%s",file);

    FILE * fs = fopen (file, "r") ;
    if ( fs == NULL ) {
       puts( "Cannot open source file" ) ;
       exit(1 ) ;
    }

    while(!feof(fs)) {
       char *Data;
       char const * rc = fgets(c, 99, fs);
       if(rc==NULL) { break; }
       if((Data = strstr(rc, "Device"))!= NULL)
       printf("%s", Data);
    }

    fclose ( fs ) ;

    return 0;
 }

私が見つけた問題:

  • 不足しているインクルードexit()
  • のパラメータがありませんexit()
  • 入力ファイル全体を実行するためのwhileループがありません。
  • 出力ファイルは使用されませんでした。
  • 'main'の戻り値がありません
  • はでData[5]
  • に変更fgetc()されましたfgets()

私は最小限の編集しかしませんでした-それはまったく完璧ではありません....

私はC++を選びます。多くのことがはるかに単純です。

于 2012-12-27T22:54:08.727 に答える
1

がハード/ファストルールではなく、入力要件が本当にこれほど単純な場合printf()は、ステートマシンとコンスタントメモリ入力をお勧めします。

int c, x = 0;                              // c is character, x is state
while(EOF!=(c=getchar())){                 // scanner entry point
  if(c == '\n') x=0;                       // newline resets scanner
  else if(x == -1) continue;               // -1 is invalid state
  else if (x < 7 && c=="Device:"[x])x++;   // advance state
  else if (x == 7 && isspace(c)) continue; // skip leading/trailing whitespace
  else if (x == 7) putchar(c);             // successful terminator (exits at \n)
  else x = -1;                             // otherwise move to invalid state
}
于 2012-12-27T23:04:54.680 に答える
1

私は2つのループでそれを行います。1つはファイルから行を取得するためのもので、もう1つは行からトークンを読み取るためのものです。

何かのようなもの:

#define BUFFSIZE 1024
int main()....

char buff[BUFFSIZE];
char delims[] = " ";
char *result = NULL;
int stop = 0;

fp = fopen("yourFile", "r");

while( fgets(buff, BUFFSIZE,fp) != NULL )  /*This returns null when the file is over*/
{
 result = strtok( buff, delims );   /*You just need to do reference to buff here, after this, strtok uses delims to know where to do the next token*/

   while(result != NULL){   /*Strtok returns null when finishes reading the given string*/
      if(strcmp(result,"Device")==0){   /*strcmp returns 0 if the strings are equal*/
         stop = 1;  /*Update the flag*/
         break;     /*Is now possible to break the loop*/
      }
      result = strtok(NULL,delims);  /*Get the next token*/
   }
   if(stop == 1) break; /*This uses the inside flag to stop the outer loop*/
}


result = strtok(NULL, delims); /*Result, now, has the string you want: 12345 */

...

このコードはあまり正確ではなく、私はそれをテストしませんでしたが、それが私がそれをやろうとする方法です。

お役に立てれば。

于 2012-12-27T23:12:14.860 に答える
1

わかりました。今回はクリアできるといいのですが。時々混乱してすみませんが、私の英語は最高ではありません。

コメント内で実装について説明します。

#define BUFFSIZE 1024
int main()....

char buff[BUFFSIZE];
char delims[] = " ";  /*Where your strtok will split the string*/
char *result = NULL;
char *device; /*To save your device - in your example: 12345*/
char *date; /*To save the date*/
int stop = 0;

fp = fopen("yourFile", "r");

while( fgets(buff, BUFFSIZE,fp) != NULL )  /*This returns null when the file is over*/
{
 result = strtok( buff, delims );   /*You just need to do reference to buff here, after this, strtok uses delims to know where to do the next token*/

   while(result != NULL){   /*Strtok returns null when finishes reading the given string*/
      if(strcmp(result,"Device")==0){   /*strcmp returns 0 if the strings are equal*/
         result = strtok(NULL, delims); /*this one gets the 12345*/
         device = (char*)malloc((strlen(result)+1)*sizeof(char)); /*Alocate the right amount of memory for the variable device*/
         strcpy(device, result); /*Now, device is "12345"*/
      }
       /*Here you do the same but for the string 'Date'*/
       if(strcmp(result,"Date")==0){   /*strcmp returns 0 if the strings are equal*/
         result = strtok(NULL, delims); /*this one gets the 12345*/
         date = (char*)malloc((strlen(result)+1)*sizeof(char)); /*Alocate the right amount of memory for the variable device*/
         strcpy(date, result); /*Now, device is "12/12/12"*/
      }
      /*And you can repeat the if statement for every string you're looking for*/
      result = strtok(NULL,delims);  /*Get the next token*/
   }
}

/*No strtok necessary here */

...

お役に立てれば。

于 2012-12-28T22:10:59.007 に答える
0

@DaveWang私の答えは大きすぎてコメントできませんでした。だからここに行く:

どういたしまして。喜んでお手伝いします。

新しいループを作成すると、テキストファイルですでに「ダウン」しているため、fgetsは機能しません。ファイルへのポインタのようなものを想像してみてください。ファイルポインタから「fgetit」するたびに、そのポインタを進めます。ファイルをリロードしたり、そのポインタを押し上げたりする機能がありますが、効率的ではありません。必要な情報がすでに渡されているので、いつかを知る方法が必要です。

私の実装を使用している場合は、ループ内で別の文字列比較を使用して行われます。if(strcmp(result、 "date")== 0)これを入力すると、結果トークンの次の値がstrtokは実際の日付です。テストする条件が2つあるので、両方を取得する前に外側のループを解除することはできません。これは、次の2つの方法で実行できます。

1-フラグの代わりに、情報が必要になるたびにインクリメントされるカウンターを使用します。そのカウンターに必要な数の情報がある場合は、外側のループを中断できます。

2-外側のループをまったく壊さないでください!:)

ただし、どちらの場合も2つの条件があるため、正しい情報を扱っていることがわかるように、ifs内でそれらを処理するようにしてください。

お役に立てれば。何でも、ただ聞いてください。

于 2012-12-27T23:39:39.640 に答える
0

cおよびDataは文字ポインタであり、文字値(のリストの先頭)へのポインタです。

fgetcのプロトタイプはint fgetc ( FILE * stream );、(1つの)整数値を返すことを意味します(整数は単一のchar値に変換可能です)。

fgetcのプロトタイプがあったとしたら、警告は表示されなかっint * fgetc ( FILE * stream );たでしょう。

于 2012-12-27T22:42:35.597 に答える