在fscanf()中使用[]

时间:2010-10-20 20:21:23

标签: c input scanf

我有一个包含以下内容的文本文件:

"abc","def","ghi"

以下内容适用于正确读取文件内容:

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;
}

然而,以下失败:

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;
}

我正在使用MSVC ++ 08.我错过了什么?我正在寻找fscanf()循环中单while的解决方案。

4 个答案:

答案 0 :(得分:7)

它的工作原理???纯粹的坏运气: - )

您的转换规范意味着

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

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

" %[\",]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

我想你想要

" %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

除此之外,scanf会在出错时返回成功转化次数或EOF。您应该将结果值与EOF进行比较,以便与1(或2或其他)进行比较:与您期望的转化次数进行比较。

if (scanf() == 3) /* expected 3 conversions */
{ /* ok */ }
else { /* oops, something went wrong */ }

答案 1 :(得分:4)

  1. 括号是他们自己的转换说明符,而不是修饰符。 %[a-zA-Z]s表示“匹配任意数量的字母字符并分配给name,然后匹配文字s。删除s个字符。
  2. 如果您希望匹配某些内容但丢弃它,请使用星号而不是垃圾缓冲区:%*[\",]
  3. 如果在文件结束前至少有一个匹配器匹配,则
  4. scanf 将不会返回EOF。这意味着当文件指针位于i之后时,您将获得错误的循环。考虑测试分配的指定符的数量,或者在末尾测试另一个"%*[\"]"以覆盖尾随的引号。
  5. 这也是第一个版本有效的原因。文字s无法匹配,但第一次转换成功,因此您获得name但不是EOF


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

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

答案 2 :(得分:2)

删除“s”转换标志,如:

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

请注意,我必须比较2而不是EOF,因为最后一个引号会在下一次迭代时被读入。

编辑:我很惊讶您的第一个代码示例也有效,但在Mac OS X上使用gcc时运行得很好,所以这不是Microsoft特有的问题。

答案 3 :(得分:0)

以下内容应该有效:

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