开发者

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 */ }


  1. Brackets are their own conversion specifier, not a modifier. %[a-zA-Z]s means "match any number of alphabetic characters and assign to name, then match a literal s. Remove the s characters.
  2. If you want to match something but discard it, use asterisk and not a garbage buffer: %*[\",].
  3. 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 the i. 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; 
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜