How to use fgets and sscanf when there is file like this?
No Nama Masakan Berat (Gram) Kalori
1 Asinan 250 208
2 Toge Goreng 250 243
3 Gado - Gado 150 295
4 Ketoprak 250 153
5 Pempek 200 384
6 Rawon 160 331
7 Soto Ayam 100 101
8 Soto Padang 100 127
9 Tongseng 120 331
10 Hamburger 125 257
11 Kerupuk Palembang 50 168
12 Kerupuk Udang 20 72
13 Mie Bakso 200 302
14 Nasi Tim Ayam 420 588
15 Pizza 125 163
16 Sate Kambing 180 729
17 Sayur Krecek 175 249
18 Siomay 100 361
19 Soto Betawi 150 135
20 Soto Makasar 150 525
21 Soto Sulung 150 86
So there is 22 line on that file. So how to scanit each format? using fgets or fscanf? I thinking that the solution maybe like this:
while(!feof(fp))
{
fgets(buffer,100,fp);
sscanf(buffer,"%d",&struct[i].number);
sscanf(buffer,"%[^\n]",struct[i].string);
sscanf(buffer,"%d",&struct[i].gram);
sscanf(buffer,"%d",&struct[i].calorie);
}
Is what im doing correct? if it's not please tell me so i won't really be curious about how to solve this problem. Sometimes i always the similar problem like this and wanna know how to solve it. Thank you.
CodePudding user response:
Because the name field can contain spaces, parsing is complicated.
Use pointers to save positions in the line. Then parse or copy from those pointers.
This is but one of several parsing strategies.
#include <stdio.h>
#include <string.h>
int main ( void) {
char buffer[100] = "";
char string[100] = "";
char *filename = "file.txt";
int number = 0;
int gram = 0;
int calorie = 0;
FILE *pf = NULL;
if ( NULL != ( pf = fopen ( filename, "r"))) {
fgets(buffer,100,pf); // get header line
while(fgets(buffer,100,pf)) // get lines until end of file
{
char *name = buffer;
int span = 0;
if ( 1 != sscanf(buffer,"%d %n",&number, &span)) {
continue;
}
name = span; // name now points to first character of name field
char *endfield = NULL;
if ( NULL != ( endfield = strstr ( name, " "))) {; // endfield points to three spaces after name field
span = endfield - name;
if ( span && span < sizeof string) {
strncpy(string,name,span); // copy span characters
string[span] = 0; // zero terminate
printf ( "%-20s", string);
}
if ( 2 == sscanf(endfield,"%d%d",&gram,&calorie)) {
printf ( " gram:= calorie:=", gram, calorie);
}
printf ( "\n");
}
}
fclose ( pf);
}
else {
perror ( filename);
}
return 0;
}
Another strategy is to use strtok
.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ( void) {
char buffer[100] = "";
char string[100] = "";
char **token = NULL; // pointer to pointer to store tokens
char *filename = "file.txt";
char *whitespace = " \t\r\n";
int limit = 0;
int number = 0;
int gram = 0;
int calorie = 0;
FILE *pf = NULL;
if ( NULL != ( pf = fopen ( filename, "r"))) {
fgets ( buffer, 100, pf); // get header line
while ( fgets ( buffer, 100, pf)) {
char *line = buffer;
char *item = NULL;
int count = 0;
while ( ( item = strtok ( line, whitespace))) {
if ( count 1 > limit) {
char **temp = realloc ( token, sizeof *token * ( count 1));
if ( NULL == temp) {
fprintf ( stderr, "realloc problem\n");
fclose ( pf);
free ( token);
exit (1);
}
token = temp;
limit = count 1;
}
token[count] = item;
count;
line = NULL;
}
if ( count < 4) { // too few tokens
continue;
}
number = 0;
gram = 0;
calorie = 0;
if ( 1 != sscanf ( token[0], "%d", &number)) { // the first token
continue;
}
if ( 1 != sscanf ( token[count - 2], "%d", &gram)) { // the next to last token
continue;
}
if ( 1 != sscanf ( token[count - 1], "%d", &calorie)) { // the last token
continue;
}
string[0] = 0;
for ( int each = 1; each < count - 2; each) {
strcat ( string, token[each]);
if ( each < count - 3) {
strcat ( string, " ");
}
}
printf ( "- %-20sgram:= calorie:=\n", number, string, gram, calorie);
}
fclose ( pf);
free ( token);
}
else {
perror ( filename);
}
return 0;
}