简体   繁体   English

在fscanf()中使用[]

[英]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? 我正在使用MSVC ++ 08.我错过了什么? I'm looking for a solution with single fscanf() in the while loop. 我正在寻找一个在while循环中使用单个fscanf()的解决方案。

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. 除此之外, scanf返回错误的成功转换次数或EOF。 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. 当您应该与1(或2或其他)进行比较时,您将结果值与EOF进行比较:与您期望的转化次数进行比较。

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. %[a-zA-Z]s表示“匹配任意数量的字母字符并分配给name ,然后匹配文字s 。删除s字符。
  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. 如果在文件结束之前至少有一个匹配器匹配,则scanf不会返回EOF This means you'll get an erroneous loop when the file pointer is after the i . 这意味着当文件指针位于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 . 文字s无法匹配,但第一次转换成功,所以你得到了name而不是EOF


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

or 要么

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

Remove the "s" conversion flag, as in: 删除“s”转换标志,如下所示:

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. 请注意,我必须比较2而不是EOF,因为最后一个引号将在下一次迭代时被读入。

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. 编辑 :我很惊讶您的第一个代码示例也有效,但它在Mac OS X上使用gcc运行得很好,因此这不是Microsoft特定的问题。

the following should work: 以下应该有效:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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