Home > Back-end >  fscanf a line separated by tab
fscanf a line separated by tab

Time:09-28

fscanf(input_file, "%s\t%d\t%d", line, &x, &y);

The goal of this code is to read a line, the file should be

Double Cheese 4 10

Double Cheese and 4 are split by \t, 4 and 10 are also split by \t so like this

Double Cheese\t4\t10

"Double Cheese" is a string needed to be stored to line.

CodePudding user response:

Instead of fscanf(), read the line with fgets() or if available: getline().

After reading the line, consider strong parsing techniques. Look for the '\t'. Allow '\t' as the first character. When parsing avoid assuming string length and its last character. Test integer values for range. Detect trailing junk.
Example:

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

typedef struct {
  const char *s; // Not null character terminated
  size_t s_length;
  long x, y;
} sll;

// Return error flag
int parse_string_tab_int_tab_int(sll *z, const char *src) {
  *z = (sll) {.s = src, .s_length = strcspn(src, "\t")};
  src  = z->s_length;
  if (src[0] != '\t') {
    return 1;
  }
  char *endptr;
  errno = 0;
  z->x = strtol(  src, &endptr, 10);
  if (src == endptr || errno || *endptr != '\t') {
    return 1;
  }
  src = endptr;
  z->y = strtol(  src, &endptr, 10);
  if (src == endptr || errno) {
    return 1;
  }
  // Consume optional trailing whitespace.
  while (isspace(*(unsigned char* )endptr)) {
    endptr  ;
  }
  return (*endptr != '\0');
}

Usage example.

#include <stdio.h>

int main(void) {
  char buf[BUFSIZ];
  if (fgets(buf, sizeof buf, stdin)) {
    sll data;
    if (parse_string_tab_int_tab_int(&data, buf)) {
      puts("Fail"); // or other TBD code
    } else {
      printf("Food: %.*s %ld %ld\n", //
          (int) data.s_length, data.s, data.x, data.y);
    }
  }
  return 0;
}

CodePudding user response:

In the OP's posted code, the %s will stop at the first whitespace character (of any type). The menu is delimited by tabs, so we can use %[] to read up to the delimiter. And then the %d specs automatically filter this and the next whitespace.

Additionally, there is a leading space before %[] because this, and the %c format, do not automatically filter leading whitespace.

And robust code will always limit potential string overflow accidents and exploits, by giving the max characters to read.

Finally, always check that scanf family functions return the expected value: the number of items successfully converted. Here, it is used to drive the loop.

#include <stdio.h>
    
int main(void) {
    
    int x, y;
    char line[100];
        
    FILE *input_file = fopen("menu.txt", "rt");
    if(input_file == NULL) {
        exit(1);
    }
    while(fscanf(input_file, "            
  •  Tags:  
  • cio
  • Related