简体   繁体   中英

Use of [] in fscanf()

I'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; 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM