How to read specifically formatted data from a file? - c

I'm supposed to read inputs and arguments from a file similar to this format:
Add id:324 name:"john" name2:"doe" num1:2009 num2:5 num2:20
The problem is I'm not allowed to use fgets. I tried with fscanf but have no idea how to ignore the ":" and seperate the string ' name:"john" '.

If you know for sure the input file will be in a well-formed, very specific format, fscanf() is always an option and will do a lot of the work for you. Below I use sscanf() instead just to illustrate without having to create a file. You can change the call to use fscanf() for your file.
#define MAXSIZE 32
const char *line = "Add id:324 name:\"john\" name2:\"doe\" num1:2009 num2:5 num3:20";
char op[MAXSIZE], name[MAXSIZE], name2[MAXSIZE];
int id, num1, num2, num3;
int count =
sscanf(line,
"%s "
"id:%d "
"name:\"%[^\"]\" " /* use "name:%s" if you want the quotes */
"name2:\"%[^\"]\" "
"num1:%d "
"num2:%d "
"num3:%d ", /* typo? */
op, &id, name, name2, &num1, &num2, &num3);
if (count == 7)
printf("%s %d %s %s %d %d %d\n", op, id, name, name2, num1, num2, num3);
else
printf("error scanning line\n");
Outputs:
Add 324 john doe 2009 5 20
Otherwise, I would manually parse the input reading a character at a time or or throw it in a buffer if for whatever reason using fgets() wasn't allowed. It's always easier to have it buffered than not IMHO. Then you could use other functions like strtok() and whatnot to do the parse.

perhaps this is what you want ?
#include <stdio.h>
#include <string.h>
int main()
{
char str[200];
FILE *fp;
fp = fopen("test.txt", "r");
while(fscanf(fp, "%s", str) == 1)
{
char* where = strchr( str, ':');
if(where != NULL )
{
printf(" ':' found at postion %d in string %s\n", where-str+1, str);
}else
{
printf("COMMAND : %s\n", str);
}
}
fclose(fp);
return 0;
}
If output of it will be
COMMAND : Add
':' found at postion 3 in string id:324
':' found at postion 5 in string name:"john"
':' found at postion 6 in string name2:"doe"
':' found at postion 5 in string num1:2009
':' found at postion 5 in string num2:5
':' found at postion 5 in string num2:20

Related

Values lossing in fscanf

The IDE I used is Clion.
I wanna read the Line-separated data stored in .txt file.
Each line contains firstname, surname, gender, ID and age, which are str, str, str, int and int.
StudentList.txt
Olivia SWANSON F 29001 20
Emma ONEILL F 7900 19
I try to use fscanf to read the data.
FILE *fp;
char fname[20];
char sname[20];
char gender[1];
int ID;
int age;
fp = fopen("C:\\Users\\Catlover\\Desktop\\DSA\\Program2\\StudentList.txt", "r");
while(fscanf(fp, "%s %s %s %d %d", fname, sname, gender, &ID, &age)!= EOF)
{
printf("%s,%s,%s,%d,%d\n", fname, sname, gender, ID, age);
}
fclose(fp);
return 0;
But the result it return looks like a little bit weird becasue it doesn't output the second value.
Result is
Olivia,,F,29001,20
Emma,,F,7900,19
Something shocks me is that the same code runned in PellesC lead to the correct result.
I used to learn C++ so there may exists some important rules in C but I didn't notice. Can anyone show that for me?
"%s" without width
Never use "%s" in a *scanf() without a width to indicate the max number of non-white-space characters to read and save. Recall that after reading, a null character is appended. Example: if the buffer size is 100, code can only read up to 99.
char gender[1]; is too small for "F".
Wrong check
fscanf(fp, "%s %s %s %d %d", ...) can return other values than 5 or EOF. As only 5 is acceptable, test against that.
Test open success
If fopen() fails, fscanf(), fclose() are bad
Other issues exist too*
But lets use start with fixing the above.
char fname[20 + 1];
char sname[20 + 1];
char gender[1 + 1];
int ID;
int age;
FILE *fp = fopen("C:\\Users\\Catlover\\Desktop\\DSA\\Program2\\StudentList.txt", "r");
if (fp) {
while(fscanf(fp, "%20s %20s %1s %d %d", fname, sname, gender, &ID, &age) == 5) {
printf("%s,%s,%s,%d,%d\n", fname, sname, gender, ID, age);
}
fclose(fp);
}
return 0;
You need to have space to accommodate null byte also.
char gender[1];
to
char gender[2];

Using fgets and sscanf for taking a string from a file

i have a file.txt structured this way:
author, "title", genre, price, copies_inStock
R. Tolkien, "The lords of the rings", Fantasy, 65.50, 31
i tried using fgets and sscanf
FILE *fp = NULL;
char string[100];
char title[30], author[30], genre[30];
float price;
int copies=0;
fp = fopen("text.txt", "r");
while(!feof(fp)) {
fgets(string, 100, fp);
sscanf(string, "%[^,],%[^,],%[^,],%f[^,],%d[^ ]", autore, titolo, genere, &prezzo, &copie);
}
fclose(fp);
printf("%s %s %s %.2f %d\n", author, title, genre, price, copies);
OUTPUT
R. Tolkien "The lord of the rings" fantasy 65,50 0
Why it don't access to the variable copies?
There are better ways? Thanks
The format specifiers on this line are incorrect
sscanf(string, "%[^,],%[^,],%[^,],%f[^,],%d[^ ]", autore, titolo, genere, &prezzo, &copie);
It should be
sscanf(string, "%[^,], %[^,], %[^,],%f,%d", autore, titolo, genere, &prezzo, &copie);
The additional spaces are to filter leading whitespace - it is not automatic with %[] (or with %c).
The %f and %d were a sort of mangled hybrid of what they should be. The conversion of those stops at the first character that cannot be used, without your intervention.
Side note: you really must check the result of scanf() function family: the number of successful conversions made.
"%f[^,]" is legal, yet certainly not what OP wants.
"%f" scans for a float, then "[^,]" scans for that 4 character sequence.
There are better ways?
Use " %n" to check scanning success. It records the offset of the scan.
Use width limits like 29 in %29[^,] to not overfill the char array.
Use a space before %29[^,] to consume optional leading whitespace.
Money is always tricky.
Do not use while(!feof(fp)). Check return from fgets().
char string[100];
char title[30], author[30], genre[30];
double price;
int copies;
FILE *fp = fopen("text.txt", "r");
if (fp) {
while(fgets(string, sizeof string, fp)) {
int n = 0;
sscanf(string, " %29[^,], %29[^,], %29[^,],%lf ,%d %n",
author, title, genre, &price, &copies, &n);
// If n==0, scan was incomplete
// If string[n], string has extra garbage
if (n == 0 || string[n]) {
fprintf(stderr, "Bad <%s>\n", string);
} else {
printf("%s %s %s %.2f %d\n", author, title, genre, price, copies);
// Robust code here would do additional work:
// Trim trailing string whitespace. Range checks on numeric values, etc.
}
}
fclose(fp);
}

Issues with sscanf in C

I am writing a program that could read a text with csv format and I am having this issue where the sscanf only parses the whole thing as one string when it is separated by ','.
For example, a code snippet below
char str[100] = "Alex,2933,89,";
char name[50] = "";
int id;
double mark;
sscanf(str, "%s,%d,%lf,", name, &id, &mark);
printf("%s\n", name);
printf("%d\n", id);
printf("%f\n", mark);
Output was:
Alex,2933,89,
896
0.000000
Which is clearly not the expected output.
But when str is edited to str = "Alex 2933 89 ", the code is giving me the correct output.
The working code:
char str[100] = "Alex 2933 89 ";
char name[50] = "";
int id;
double mark;
sscanf(str, "%s %d %lf ", name, &id, &mark);
printf("%s\n", name);
printf("%d\n", id);
printf("%f\n", mark);
Correct Output:
Alex
2933
89.000000
Can I know how do I fix this?
%s stops at white space, the fact that you put a , in the format string does not change this behavior. You should use the %[^,] conversion specification.
Change the code this way:
char str[100] = "Alex,2933,89,";
char name[50] = "";
int id;
double mark;
if (sscanf(str, "%49[^,],%d,%lf,", name, &id, &mark) == 3) {
printf("%s\n", name);
printf("%d\n", id);
printf("%f\n", mark);
}
Note however that %[^,] cannot parse empty fields. If the CSV line may contain empty fields, such as ,23,89.0, sscanf() will fail to convert name because no character matches the %[^,] specification. If you have such lines in the source file, you should parse the string fields manually with strchr() or strcspn().

get the values for each line in the file in c

I need to read this main.txt file:
STUDENT ID 126345
TEACHER MATH CLASS 122
And i need to get each values from this file . If this main.txt file was like this:
STUDENT ID 126345
TEACHER ID 3654432
I could do it like this:
#include <stdio.h>
int main(){
FILE *ptr_file;
int id;
char string1[100],string2[100];
ptr_file = fopen("main.txt","r");
while(fscanf(ptr_file,"%s %s %d",string1,string2,id) != EOF){
}
}
But I can't use fscanf() function because space amount between these values is not equal for each line. How can i get every value in line by line like this code ?
If every line has 3 values separated by empty spaces (or tabs), then
fscanf(ptr_file,"%s %s %d",string1,string2,&id);
is OK (and note that I used &id instead of id), because %s matches a sequence of non-white-space characters, so it
doesn't matter how many empty spaces are between the values, %s will consume
the empty spaces:
#include <stdio.h>
int main(void)
{
const char *v = "STUDENT \t ID \t 126345";
int id;
char string1[100],string2[100];
sscanf(v, "%s %s %d", string1, string2, &id);
printf("'%s' '%s' %d\n", string1, string2, id);
return 0;
}
which prints
$ ./a
'STUDENT' 'ID' 126345
In general the most robost solution would be to read line by line with fgets
and parse the line with sscanf as you have more control over when a line has a
wrong format:
char buffer[1024];
while(fgets(buffer, sizeof buffer, stdin))
{
int id;
char string1[100],string2[100];
if(sscanf(buffer, "%99s %99s %d", string1, string2, &id) != 3)
{
fprintf(stderr, "Line with wrong format\n");
break;
}
// do something with read values
}
edit
User Weather Vane points out that the line might have 3 or 4 values, then you
could do this:
char buffer[1024];
while(fgets(buffer, sizeof buffer, stdin))
{
int id;
char string1[100],string2[100],string3[100];
res = sscanf(buffer, "%99s %99s %99s %d", string1, string2, string3, &id);
if(res != 4)
{
int res = sscanf(buffer, "%99s %99s %d", string1, string2, &id);
if(res != 3)
{
fprintf(stderr, "Line with wrong format, 3 or 4 values expected\n");
break;
}
}
if(res == 3)
printf("'%s' '%s' %d\n", string1, string2, id);
else
printf("'%s' '%s' '%s' %d\n", string1, string2, string3, id);
}

Why is my program stopping before reading the txt file?

My code keeps closing before reading the file, I made a comment where it closes. Does anyone know why it wont work? I showed it to my lecturer but she couldn't figure it out and then she had to leave so I was wondering if anyone here could figure it out!
#include <stdio.h>
#include <stdlib.h>
#define RESULT_MAX = 100;
#define RESULT_MIN = 0;
int main()
{
int studentId;
char firstName[20];
char lastName[20];
int result;
FILE *fPtr;
if ((fPtr = fopen("student.txt", "w")) == NULL)
{
printf("File could not be opened\n");
//exit(0);
}
else
{
printf("Enter the Id, first name, last name and result\n");
scanf("%d %s %s %d", &studentId, firstName, lastName, &result);
while(!feof(stdin) )
{
fprintf(fPtr, "%d %s %s %d\n", studentId, firstName, lastName, result);
scanf("%d %s %s %d", &studentId, firstName, lastName, &result);
}
fclose(fPtr);
}//else end
// MY PROGRAM ENDS HERE AND WONT CONTINUE!
if ((fPtr = fopen("student.txt", "r")) == NULL)
{
printf("File could not be opened\n");
//exit(0);
}
else
{
printf("Id, first name, last name, result ");
fscanf(fPtr, "%d %s %s %d", &studentId, firstName, lastName, &result);
while(!feof(fPtr) )
{
printf("%d %s %s %d \n", studentId, firstName, lastName, result);
fscanf(fPtr, "%d %s %s %d", &studentId, firstName, lastName, &result);
}//end while
fclose( fPtr );
}//end if
}
the problem is actually the line: 'while(!feof(stdin) )'
because feof() only becomes valid when the program
tries to read past the end of the 'stdin' file.
This is something that cannot be accomplished
suggest
modifying the program to:
1) read into a local buffer[] array, in a loop,
2) using fgets() as the loop control
3) have a leading 'q' (or similar) as an indication of having read all input
4) output a prompt for every input line
5) if going to parse the fields, parse them using
strtok()/atoi() strncpy() strncpy() atoi()
or perhaps
sscanf()
6) check first char of input buffer[] for the end marker (the 'q' above)
to exit the input loop before parsing
there is a similar problem with the
loop reading the file
I.E. do not use feof() for loop control
rather use fgets()
to differentiate each line of input written to the file, modify
the fprintf(fPtr, ... ) format string to include a trailing '\n'

Resources