【问题标题】:C - how to get fscanf() to determine whether what it read is only digits, and no charactersC - 如何让 fscanf() 确定它读取的内容是否只有数字,没有字符
【发布时间】:2010-04-11 03:33:02
【问题描述】:

假设我有一个 csv,每个值都是一个整数。所以第一个值是整数100

我希望 fscanf() 读取这一行,或者告诉我它只是一个整数,或者不是。因此,它将通过100 但在100t 上失败。我一直在努力工作的是“%d”,其中逗号是我的 CSV 的分隔符。所以整个函数是

fscanf(fp, "%d,", &count)

不幸的是,这在“100t”上失败,在“100”上有效,在“t”上有效。所以它只是不区分 100100t (当然,所有这些数字后跟逗号

【问题讨论】:

    标签: c scanf


    【解决方案1】:

    请改用strtol

    【讨论】:

    • 如果我不知道第一个 int 可能有多长怎么办?我需要事先声明字符串数组以传递给 fscanf。大概我可以使这些整数之一变得巨大,这将需要初始化一个巨大的数组。
    • @hatorade - 不,int 类型会在您可以存储在 char[80] 中的最大数字之前很久就溢出。
    【解决方案2】:

    你没有。

    问题是fscanf() 不是很有用。处理它的最佳方法是读取整行(或行的重要部分),然后分析字符串。这是一个例子:

    int value;
    char *extra;
    char buffer[100];
    
    // read in some data from the buffer
    fgets(buffer, sizeof buffer, stdin);
    
    // parse out a digit, if we can
    i = strtol(buffer, &extra, 0);
    

    此时可以查看extra是否有多余的字符,表示该行不是纯数字,或者extra指向buffer的开头,表示没有要解析的数字。

    【讨论】:

      【解决方案3】:

      fscanf 实际上比其他一些答案所暗示的要有用得多——但大多数人不太了解它,也不知道如何发挥其全部功能。

      有用的点:首先,使用 fscanf 的返回值——它告诉你有多少项目被转换了。其次,“扫描集”转换非常有用。考虑以下情况(我使用sscanf 来避免需要外部文件,但fscanf 仅在读取的来源上有所不同):

      #include <stdio.h>
      
      int main() { 
          int i;
          char *test[] = {
              "100,",    // should succeed.
              "100t,",   // should fail.
              "t"        // should also fail.
          };
      
          for (i=0; i<3; i++) {
              int count;
              char ch[2];
              if (2 == sscanf(test[i], "%d%[,]", &count, &ch))
                  fprintf(stderr, "Conversion of \"%s\" succeeded.\n", test[i]);
              else
                  fprintf(stderr, "Conversion of \"%s\" failed.\n", test[i]);
          }
          return 0;
      }
      

      【讨论】:

        【解决方案4】:

        怎么样

        fscanf(fp, "%d%c", &count, &aChar)
        

        如果 aChar != ',' && != '\n' 那么你不只有一个整数

        【讨论】:

          【解决方案5】:

          对非 100% 控制的输入使用 scanf 函数可能会很痛苦,这样才能避免错误,最好使用 fgets() 读取行,然后使用 strtok() 将行拆分为标记,然后可以转换。

          在像“100t”这样的一个令牌上使用atoi会产生0,而“100”会产生100

          【讨论】:

            【解决方案6】:

            scanf() 系列函数不太擅长检测此类错误。这并非不可能(请参阅 Jerry Coffin 的回答,该答案有效,但 IMO 难以概括),但 IMO 并没有那么强大。更好的选择是使用fgets() 将输入读取为文本,使用strtok() 或类似方法进行标记,然后使用strtol()strtod() 将标记转换为数值:

            char buffer[LINE_SIZE];
            while (fgets(buffer, sizeof buffer, inFile))
            {
              char *token;
              char *newline = strchr(buffer, '\n');
              if (newline) 
                *newline = 0;
              token = strtok(buffer, ",");
              while (token)
              {
                char *chk;
                int value = (int) strtol(token, &chk, 10);
                if (!isspace(*chk) && *chk != 0)
                {
                  printf("%s is not a valid integer\n", token);
                }
                else
                {
                  printf("successfully read integer value %d\n", val);
                }
                token = strtok(NULL, ",");
              }
            }
            
            if (feof(inFile))
            {
              printf("Hit end-of-file\n");
            }
            else
            {
              printf("Error during read\n");
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-06-25
              • 2013-01-07
              • 1970-01-01
              • 1970-01-01
              • 2014-05-18
              • 2023-03-23
              相关资源
              最近更新 更多