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

fgetc返回一个整数值,即字符,提升为 int。我想你的意思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

好的,希望我这次可以清除它。抱歉,如果我有时会感到困惑,但我的英语不是最好的。

我将在评论中解释实现:

#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 回答
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

我的建议是使用 fread 来读取所有文件。您可以逐个字符地读取它,但是恕我直言(这里是个人口味),获取包含所有字符的字符串然后对其进行操作更简单。

这是函数原型:

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

如果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 回答
0

c并且Data是字符指针,指向(列表的开头)字符值的指针。

fgetc的原型int fgetc ( FILE * stream );意味着它返回(一个)整数值(整数可转换为单个 char 值)。

如果fgetc' 的原型本来是int * fgetc ( FILE * stream );警告就不会出现。

于 2012-12-27T22:42:35.597 回答
0

@Dave Wang 我的回答太大了,不能发表评论。所以这里是:

别客气。乐意效劳。

如果您创建一个新循环,则 fgets 将无法工作,因为您已经在文本文件中“关闭”。想象一下像一个指向文件的指针,每次你从一个文件指针'fget',你推进那个指针。您具有重新加载文件或向上推该指针的功能,但效率不高,您已经通过了您想要的信息,必须有办法知道何时。

如果你使用我的实现,那是通过在循环中使用另一个字符串比较来完成的: if(strcmp(result,"date") == 0) 如果你输入这个 if,你知道结果标记中的下一个值strtok 是实际日期。由于您现在有两个条件要测试,因此您不能在同时拥有这两个条件之前打破外循环。这可以通过两种方式实现:

1-而不是标志,使用每次需要信息时递增的计数器。如果该计数器具有您想要的相同数量的信息,您可以打破外循环。

2-根本不要打破外循环!:)

但是在这两种情况下,由于有两个条件,请确保在 ifs 中处理它们,这样您就知道您处理的是正确的信息。

希望这可以帮助。有什么,随便问问。

于 2012-12-27T23:39:39.640 回答