Question

Say I have a text file like this:

User: John

Device: 12345

Date: 12/12/12

EDIT:

I have my code to successfully search for a word, and display the info after that word. However when I try to edit the code to search for 2 or 3 words and display the info after them instead of just 1 word, I cannot get it to work. I have tried adding codes into the same while loop, and creating a new while loop for the other word, but both doesn't work. There must be something I am doing wrong/not doing.

Please advice, thanks!

Here is my code:

 #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;

 }
Was it helpful?

Solution

Ok, hope I can clear it this time. Sorry if I get confusing sometimes but my english is not the best.

I'll explain the implementation inside comments:

#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 */

...

Hope this helps.

OTHER TIPS

fgetc returns an integer value, which is character, promoted to int. I suppose you meant fgets which reads a whole line, but you need to reserve memory for it, for example:

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

Some helpful links.

There are a couple of problems in your code: basically it never compiled.

Here is a version with small cleanups - which at least compiles:

#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;
 }

Problems I found:

  • Missing include for exit()
  • Missing parameter for exit()
  • Missing while loop to run through the whole input file.
  • The output file was never used.
  • Missing return value of 'main'
  • Fancy Data[5]
  • Changed fgetc() to fgets()

I only did minimal edits - it's not perfect at all....

IMHO I would go for C++: many things are much simpler there.

If printf() isn't a hard/fast rule, and the input requirements are really this simple, I'd prefer a state-machine and a constant-memory input:

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
}

I would do that with two loops: one to get a line from the file and other to make tokens from the line read.

something like:

#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 */

...

this code is not very accurate and I didn't tested it, but thats how I would try to do it.

Hope this helps.

My suggestion is to use fread to read all the file.You could read it character by character, but IMHO (a personal taste here) it's simpler to get a string containing all the characters and then manipulating it.

This is the function prototype:

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

It returns the number of elements read.

For example:

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

Then you can manipulate the string and divide it in tokens.

EDIT

There is a nice reference with also an example of how dividing a string into tokens here:

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

c and Data are char-pointers, pointers to (the start of a list of) character value(s).

fgetc's prototype is int fgetc ( FILE * stream ); meaning that it returns (one) integer value (an integer is convertible to a single char value).

If fgetc's prototype would've been int * fgetc ( FILE * stream ); the warning wouldn't have appeared.

@Dave Wang My answer was too big to be a comment. So here it goes:

You're welcome. Glad to help.

If you make a new loop, the fgets won't work because you are already 'down' in the text file. Imagine something like a pointer to the file, every time you 'fget it' from a file pointer, you advance that pointer. You have functions to reload the file or push that pointer up, but it is not efficient, you've already passed by the information you want, there must be a way to know when.

If you're using my implementation, that is done by using another string compare inside the loop: if(strcmp(result,"date") == 0) If you enter this if, you know that the next value in result token with strtok is the actual date. Since you have now two conditions to be tested, you can't break the outer loop before having both of them. This can be accomplished by two ways:

1-Instead of a flag, use a counter that is incremented everytime you want an information. If that counter has the same number of information you want, you can break the outer loop.

2-Don't break the outer loop at all! :)

But in both, since there are 2 conditions, make sure you treat them inside the ifs so you know that you dealing with the right information.

Hope this helps. Anything, just ask.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top