0

I have an input file with the following form

i 176064 Patterson Denise 8.58 11 DEN 15788 
q 188464
ra 148702 167443
a  73131
d 163464
f 6.00
ct 73131 PHY
b 3
p 15703
pe
m 144626 6.51 8
e

The first character in each line[i,q,ra,a...] represents an code to a function , while the rest are values that I must store into variables,depending on that code. What's the best way to achieve this ? I have been thinking about using fscanf but each line does not have a specific format, the format itself depends on the code [i,q,ra,a,b..]

Eug G
  • 39
  • 1
  • 3
  • 2
    With `strtok`. Read the lines with `fgets` and examine each token, to decide how to proceed. – Weather Vane Oct 19 '16 at 22:36
  • Whatever you do, don't use anything like fscanf. Absolutely the wrong tool for the job. – Steve Summit Oct 20 '16 at 00:02
  • Note that some of the 'codes' are multiletter codes, so it is the first 'word' rather than the 'first character' that represents the code to a function. Since the `scanf()` family of functions don't care about lines, you can't use them to do the file input. You need to read the lines (`fgets()` for example) and then analyze them (`sscanf()` may be OK — check [Using `sscanf()` in a loop](http://stackoverflow.com/questions/3975236/how-to-use-sscanf-in-loops), for example). – Jonathan Leffler Oct 20 '16 at 00:42

1 Answers1

1

To read a line, use fgets()

char buffer[100];
while (fgets, buffer, sizeof buffer, istream) != NULL) {

Then scan the line against the various formats, each ending with " %n". "%n" records the scan position, if it got that far. Additional tests could check for extraneous extras character starting at n.

  int num1, num2, num3;
  char last[sizeof buf];
  char first[sizeof buf];
  char code[sizeof buf];
  double rate;
  int n = 0;
  //               v..v..v..v...v..v..v spaces optional here
  sscanf(buffer, "i %d %s %s %lf %d %s %d %n",
    &num1, last, first, &rate, &num2, code, &num3, &n);
  if (n) {
    Handle_i();
    continue;
  }
  sscanf(buffer, "q %d %n", &num1, &n);
  if (n) {
    Handle_q();
    continue;
  }
  sscanf(buffer, "ra %d %n", &num1, &num2, &n);
  if (n) {
    Handle_ra();
    continue;
  }
  sscanf(buffer, "e %n", &n);
  if (n) {
    Handle_e();
    continue;
  }
  ...
  fail();
}

As each format begins with a unique letter pattern, the sscanf() will quickly exit on mis-match.

Alternative, code could parse out the initial letters for a slightly more efficient decision tree. Suspect profiling will show little performance difference.

As with any complex format, consider how one would maintain the code and it is bound to evolve.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • ok i got this , can you explain me once again what the n integer exactly does ? – Eug G Oct 20 '16 at 11:05
  • ok i got this , can you explain me once again what the n integer exactly does ? – Eug G Oct 20 '16 at 11:56
  • @EugG `int n = 0;` gives `n` the initial value of 0. `sscanf(buffer, "... %n", .... &n);` saves into `n` the offset of the scan of the string `buffer[]` at that point in the scan. If the scan never reaches the `"%n"` because of an earlier mis-match in the scan, `n` is not changed. – chux - Reinstate Monica Oct 20 '16 at 15:44