Using [] in fscanf ()

I have a text file with the following contents:

"abc","def","ghi" 

The following works to read the contents of the file correctly:

 int main() { char name[1024] = {0}; FILE *file = fopen("file.txt", "r"); while(1) { if (fscanf(file, " %[\",]s ", name) == EOF) break; if (fscanf(file, " %[a-zA-Z]s ", name) == EOF) break; printf("%s\n", name); } return 0; } 

However, the following fails:

 int main() { char name[1024] = {0}, garbage[5]; FILE *file = fopen("file.txt", "r"); while(1) { if (fscanf(file, " %[\",]s%[a-zA-Z]s ", garbage, name) == EOF) break; printf("%s\n", name); } return 0; } 

I am using MSVC ++ 08. What am I missing? I am looking for a solution with single fscanf() in a while .

+6
c input scanf
source share
4 answers

It works??? Pure bad luck :-)

Your conversion specifications mean

 " %[\",]s " ^= optionally skip whitespace ^== read a literal 's' ^^^^^^=== read an unlimited string of quotes and commas ^========= optionally skip whitespace 

and

 " %[a-zA-Z]s " ^= optionally skip whitespace ^== read a literal 's' ^^^^^^^^^=== read an unlimited string of letters ^============ optionally skip whitespace 

and

 " %[\",]s%[a-zA-Z]s " ^= optionally skip whitespace ^== read a literal 's' ^^^^^^^^^=== read an unlimited string of letters ^============ read a literal 's' ^^^^^^============= read an unlimited string of quotes and commas ^=================== optionally skip whitespace 

I think you want

 " %4[\",]%1023[a-zA-Z] " ^= optionally skip whitespace ^^^^^^^^^^^^^== read a string of at most 1023 letters ^^^^^^^=============== read a string of at most 4 quotes and commas ^====================== optionally skip whitespace 

In addition, scanf returns the number of successful conversions or EOF on error. You compare the value of the result with EOF, when you should compare with 1 (or 2 or something else): compare the number of expected conversions.

 if (scanf() == 3) /* expected 3 conversions */ { /* ok */ } else { /* oops, something went wrong */ } 
+7
source share
  • Brackets are their own conversion specifier, not a modifier. %[a-zA-Z]s means "matches any number of alphabetic characters and is assigned a name , and then matches the literal s . Remove the characters s .
  • If you want to match something, but discard it, use an asterisk and not the garbage buffer: %*[\",] .
  • scanf will not return EOF if at least one qualifier is matched before the file completes. This means that you will get an error loop when the file pointer is after i . Consider checking the number of assigned qualifiers or another "%*[\"]" at the end to split the trailing caves.

That is why the first version worked. The literal s did not match, but the first conversion succeeded, so you got name , but not EOF .


 if (fscanf(file, " %*[\",]%[a-zA-Z] ", name) < 1) break; 

or

 fscanf(file, " %*[\",]%[a-zA-Z]%*[\"] ", name) 
+4
source share

Remove the conversion flag s, as in:

 if (fscanf(file, " %[\",]%[a-zA-Z] ", garbage, name) < 2) 

Note that I have to compare with 2, not EOF, since the last quote will be read at the next iteration.

EDIT . I am surprised that your first code sample also works, but it did a great job of gcc on Mac OS X, so this is not a Microsoft problem.

+2
source share

the following should work:

  if (fscanf(file, " %[\",]%[a-zA-Z] ", garbage, name) == EOF) break; 
0
source share

All Articles