Use of [] in fscanf()
I开发者_如何学Go've a text file with following contents:
"abc","def","ghi"
The following works to read the file contents properly:
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'm using MSVC++ 08. What am I missing? I'm looking for a solution with single fscanf()
in the while
loop.
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
Other than that, scanf
returns the number of successful conversions or EOF on error. You're comparing the result value with EOF when you should be comparing to 1 (or 2, or whatever): compare to the number of conversions you expect.
if (scanf() == 3) /* expected 3 conversions */
{ /* ok */ }
else { /* oops, something went wrong */ }
- Brackets are their own conversion specifier, not a modifier.
%[a-zA-Z]s
means "match any number of alphabetic characters and assign toname
, then match a literals
. Remove thes
characters. - If you want to match something but discard it, use asterisk and not a garbage buffer:
%*[\",]
. - scanf won't return
EOF
if at least one specifier matched before the file ended. This means you'll get an erroneous loop when the file pointer is after thei
. Consider testing the count of specifiers assigned, or another"%*[\"]"
at the end to slurp up the trailing quotes.
This is also why the first version worked. The literal s
failed to 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)
Remove the "s" conversion flag, as in:
if (fscanf(file, " %[\",]%[a-zA-Z] ", garbage, name) < 2)
Note that I must compare to 2 rather than EOF since the last quotation mark will get read-in on the next iteration.
EDIT: I'm surprised your first code sample works too, but it ran just fine with gcc on Mac OS X, so this isn't a Microsoft-specific issue.
the following should work:
if (fscanf(file, " %[\",]%[a-zA-Z] ", garbage, name) == EOF)
break;
精彩评论