Skipping strings between separator with sscanf() - c

I've got a couple of strings structed like this:
1|36901|O|173665.47|1996-01-02|5-LOW|Clerk#000000951|0|nstructions sleep furiously among |
I want to extract the fields in position 0, 1, 3, 7, in this case 1, 36901, 173665.47 and 0.
I've tried
sscanf(line, "%d|%d|%*c|%lf|%*s|%*s|%*s|%d|%*s|", &rec.order_key, &rec.cust_key, &rec.total_price, &rec.ship_priority);
printf("%d %d %lf %d", rec.order_key, rec.cust_key, rec.total_price, rec.ship_priority);
and expecting to get
1 36901 173665.470000 0
instead I got
1 36901 173665.470000 1
so I guess I did something wrong with the skipping, but I just can't figure it out.

I figure this out: the sscanf() does greedy matching, so the string being skipped is too long. Using
sscanf(line, "%d|%d|%*c|%lf|%*[^|]|%*[^|]|%*[^|]|%d|%*[^|]|",
&rec.order_key, &rec.cust_key, &rec.total_price, &rec.ship_priority);
solved the problem.

Related

fscanf won't read the integer values in text file

I am using an fscanf to read a sequence of 8 values of zero or one at the end of the line, but it looks like the array is never having a value read to it.
It is reading this from the text file:
Chilli Con Carne,Chilli_Con_Carne.txt, 15, 25, 100,0,0,0,0,0,0,0,0
Spaghetti Bolognese,Spaghetti_Bolognese.txt, 30, 75, 150, 0, 0, 0, 0, 0, 0, 1, 0
Frittata,Frittata.txt, 10, 15, 160, 1, 1, 0, 0, 0, 0, 0, 0
Korean Beef,Korean_Beef.txt, 20, 30, 100, 0, 0, 0, 0, 0, 1, 0, 1
Trawlers Pie, Trawlers_Pie.txt, 20, 30, 100,1,1,0,1,0,0,0,0
This is the loop I am using which contains the fscanf that is not reading the recipeAllergies:
while (!feof (cookBook)){
fscanf(cookBook, "%20[^,], %20[^,], %d, %d, %d", recipeName, recipeFileName, &prepTime, &cookTime, &calories);
printf("%s ", recipeName);
for (i = 0; i < 8; i++){
fscanf(cookBook, "%d,", &recipeAllergies[i]);
printf("%d %d\n", recipeAllergies[i], userAllergies[i]);
if ((userAllergies[i] + recipeAllergies[i]) == 2){
notSuitable = 1;
}
}
fgets(ignore_line, sizeof(ignore_line), cookBook);
if (notSuitable == 0){
(suitableRecipes[totalSuitable]. recipeName, recipeFileName, prepTime, cookTime, calories);
totalSuitable++;
}
}
Any help is greatly appreciated.
The inner loop has a format string "%d," so fscanf() is looking for integers followed by a comma. There is no comma on the end of the input lines, so scanf() will return indicating an error.
Either add commas at the end of the input lines, or change the loop so it doesn't look for a comma the 8th time. The latter is preferable.
Although you didn't ask, a few other concerns you might want to address with your code......
Looping on feof() is a really bad idea, because (among other problems) if no error is detected in the loop body, it will attempt to read one more
line of input from your file than exists.
Always check the return value of functions like fscanf() and fprintf(), since they can fail.
Mixing fgets() with fscanf() on the same file is a bad idea, because
they respond to file contents differently (e.g. in how they respond
to a newline) and using them in combination can result in spurious
loss of data. [More generally, the same goes for mixing styles of
input. Don't mix manners of input for the same file.
Mixing character oriented input (e.g. fgetc()), line oriented input
(e.g. fgets()), and/or formatted input (e.g. fscanf()) can all cause spurious problems if they are used on the same stream.]
The first statement in the if (notSuitable == 0) block doesn't do
anything. I assume you left out the name of the function to be
called.
First, process comma after calorie while using fgetc. After that, read each number.
You are also expecting comma from last digit where as this might not be the case.
Alternatively, you can discard each comma separately by using fgetc.
You can try following code snippets in your for loop.
for (i = 0; i < 8; i++){
fgetc(cookBook); //To discard/read comma
fscanf(cookBook, "%d", &recipeAllergies[i]);
printf("%d %d\n", recipeAllergies[i], userAllergies[i]);
if ((userAllergies[i] + recipeAllergies[i]) == 2){
notSuitable = 1;
}
}
Also see the link mentioned in question's comment. Why is “while ( !feof (file) )” always wrong?

wcstok() not working correctly?

I'm trying to get each line in a loop for a wchar_t string using wcstok(), that string is supposed to contain at least two lines, the latest 'wcstok(0, L"\n")' is getting always null result and I'm getting the value of i using printf as 1 only instead of 2 or higher, but the problem got solved when doing #if 0 instead of #if 1.
this is the code below:
wchar_t* w;
wchar_t* line;
int j;
wchar_t**** lines;
int** linescount;
......
int i=0;
#if 1 //problem get solved when changing to #if 0
line = wcstok(w, L"\n");
do{
((*linescount)[j])++;
}while(line=wcstok(0, L"\n"));
(*lines)[annex] = calloc(sizeof(wchar_t**), (*linescount)[j]);
#endif
line = wcstok(w, L"\n");
do{
#if 1 //problem get solved when changing to #if 0
(*lines)[j][i] = calloc(sizeof(wchar_t*), wcslen(line)+1);
wcscpy((*lines)[j][i], line);
#endif
i++;
}while(line=wcstok(0, L"\n"));
printf("i = %d\n", i); /*prints the i value to check if the latest line=wcstok(0, L"\n") worked correctly or not*/
so what's supposed the cause of this problem? and how can I solve it? please help.
The wcstok modifies the string passed in as argument so once you have run your loop to count lines the buffer is basically kaputt.
It seems like overkill to use wcstok to count lines when you easily could just loop through the buffer counting number of \n.

Can't write int to file using fwrite

I'm trying to format my keylog output so it shows time:
t = time(0);
now = localtime(&t);
if(now->tm_min != prevM && now->tm_hour != prevH)
{
prevM = now->tm_min;
prevH = now->tm_hour;
fwrite("[", 1, sizeof(WCHAR), keylog);
fwrite(&prevH, 1, sizeof(int), keylog);
fwrite("]", 1, sizeof(WCHAR), keylog);
fwrite(" ", 1, sizeof(WCHAR), keylog);
fflush(keylog);
}
but instead of readable number I get "[ DLE NUL ] " written in my file, where DLENUL is question mark.
How do I make it to write a readable number?
Use fprintf as others are also suggesting.
Reason:
fwrite is generally used to write in binary files to write blocks of same type of data.
The data you are writing looks like a character string, you can use fprintf with following syntax to write your complete data in the file.
fprintf(keylog, "[%d] ", prevH);
It seems you are writing wide characters (as you use wchar). You can use different format specifiers accordingly.
Instead of
fwrite(&prevH, 1, sizeof(int), keylog);
try
fprintf(keylog, "%d", prevH);
With fwrite you are storing the binary representation. If you want to store a textual representation you can use fprintf.
As others have already suggested, you could use fprintf when writing text to a file.
More specifically, when writing WCHARs you can use either:
fwprintf(file, L"%c\n",outputChar);
or:
fprintf(file, "%lc", outputChar);
For more information, have a look at the documentation of the function:
http://www.cplusplus.com/reference/cwchar/fwprintf/

Can I call sscanf mutliple times on the same string?

I'm trying to read a line from a file, I grab a line line using fgets. I then try to use sscanf to parse it. Sometimes I'll call sscanf and find out it returns the wrong number of arguments. So then I'll try reparse the same line string. Sometimes it works, sometimes it doesn't (which is leading me to believe that the problem isn't sscanf but something else in my code). Here's an example of what I mean:
i = sscanf(line,"%d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d\n", &faceV1, &faceUV1, &faceN1, &faceV2, &faceUV2, &faceN2, &faceV3, &faceUV3, &faceN3,
&faceV4, &faceUV4, &faceN4);
if(i == 12) {
//We gotta quad...
printf("Model.c: Quads not supported\n");
} else if(sscanf(line,"%d/%d/%d %d/%d/%d %d/%d/%d\n", &faceV1, &faceUV1, &faceN1, &faceV2, &faceUV2, &faceN2, &faceV3, &faceUV3, &faceN3) == 9) {
//Doesn't do what I expect!
...
However if I get rid of i = sscanf... and the check for i == 12 and go straight to if(sscanf(line,"%d/%d/%d %d/%d/%d %d/%d/%d\n", &faceV1, &faceUV1, &faceN1, &faceV2, &faceUV2, &faceN2, &faceV3, &faceUV3, &faceN3) == 9) it will work as expected.
So back to the title of this question, can I call sccanf multiple times on the same string? Am I calling it wrong? Or should I look elsewhere in my code for the problem?
Short answer YES you can sscanf the same string multiple times.
Your problem is that having "\n" in your string does not do what you expect...
It matches ANY white-space character space, tab, \r, and not just \n.
So you need to check for the end-of-line after scanf'ing.

flex i am confused

input to lexer
abc gef4 44jdjd ghghg
x
ererete
xyzzz
55k
hello wold
33
my rules
rule1 [0-9]+[a-zA-Z]+
rule2 [x-z]
rule3 .*
{rule1} {
printf("%s \n", yytext);
}
{rule2} {
printf("%s \n", yytext);
}
{rule3} {
// prints nothing
}
output :-
x
55k
I cannot understand the output ? Can someone please help me.
The first character of the input neither matches rule1 nor rule2. Instead rule3 eats input up to the end of line. The same happens on line 3, 4, 6, and 7. You probably want a less greedy rule3, i.e. one that doesn't consume the spaces:
[^ \t\n]* /* Do nothing */
Then 44jdjd is being found by rule1.

Resources