【问题标题】:How to read only integers from a file with strings, spaces, new lines and integers in C如何从 C 中包含字符串、空格、换行符和整数的文件中仅读取整数
【发布时间】:2017-03-24 00:47:22
【问题描述】:

我知道这是一个非常琐碎的问题,但我只需要快速帮助。我一直试图弄清楚这一点。我要做的只是从具有以下格式的文本文件中读取整数

 8 blah blah
 10 blah blah
 2 blah blah
 3 blah blah

我最终只想获取数字,将它们存储在数组中,然后将这些数字放入 BST。当我有一个只有数字但没有指定文件格式的文件时,我的 BST 工作正常。

blah 是什么并不重要,我只想获取数字并将它们存储在数组中。如果我取出blah's,我可以做到这一点。使用fscanf,我得到了存储第一个数字8 的代码,但它停在那里。同样在此示例中,有四行,但文件中有多少行并不重要。可能是 12 或 6。我怎样才能正确地做到这一点。以下是我解决这个问题的糟糕尝试。

 fscanf(instructionFile, "%d", &num);

我也试过做类似的事情

 while(!feof(instructionFile)){
  fscanf("%d %s %s", &num, string1, string2);
 }

存储所有内容并且只使用整数,但是当我这样做时,我的 BST 不起作用。

【问题讨论】:

  • 停止使用 fscanf。使用fgets,然后用strtol解析
  • 数字总是在行首吗?线路中总是有一个数字吗?一行可以有很多数字吗?数字可以用字母或标点符号包围吗?您不必担心标志吗?
  • @JonathanLeffler 我让它工作了,但我们可以假设数字总是行的开头,我们不必担心标志,每行只有一个数字。我可以想象如果在不同的地方每行有多个数字,这将是多么复杂
  • 很高兴你得到了解决。是的,我在之前的评论中提到的那些问题都让我更难处理。这取决于上下文,听起来您有一组相当良性的数据可供使用。不要忘记接受最有帮助的答案,假设其中至少有一个是有帮助的。这样可以让其他人知道问题已解决。

标签: c integer binary-search-tree scanf


【解决方案1】:

使用fgets() 获取一行输入,使用sscanf() 获取整数。在您使用fscanf() 的示例中,第一次调用将读取int,而下一次调用将失败,因为输入流中的下一项不是int。每次失败后,错误的输入都会留在输入流中。通过一次获取一行,您可以在空闲时扫描该行,然后再获取另一行输入。

以下是您可以如何执行此操作的示例。并注意不要使用feof() 来控制读取循环;相反,使用来自fgets() 的返回值。此代码假定行中的第一个条目是您想要的数据,可能带有前导空格。可以针对稍微复杂的情况修改格式字符串。如果您需要更好地控制行的解析,也可以使用strtok()

#include <stdio.h>
#include <stdlib.h>

#define MAX_LINES  100

int main(void)
{
    FILE *fp = fopen("data.txt", "r");
    if (fp == NULL) {
        fprintf(stderr, "Unable to open file\n");
        exit(EXIT_FAILURE);
    }

    char buffer[1000];
    int arr[MAX_LINES];
    size_t line = 0;

    while ((fgets(buffer, sizeof buffer, fp) != NULL)) {
        if (sscanf(buffer, "%d", &arr[line]) != 1) {
            fprintf(stderr, "Line formatting error\n");
            exit(EXIT_FAILURE);
        }
        ++line;
    }

    for (size_t i = 0; i < line; i++) {
        printf("%5d\n", arr[i]);
    }

    fclose(fp);

    return 0;
}

最好在调用sscanf() 之前添加一个空行检查;现在空行被认为是格式错误的数据。

示例文件的输出:

    8
   10
    2
    3

【讨论】:

    【解决方案2】:

    如果您只想从一堆乱七八糟的文件中挑选出整数,那么您实际上需要使用指针识别每个开始数字(或以 - 开头的负数符号)转换每个整数一次找到一个。您可以使用指针和sscanf 执行此操作,也可以使用strtol 执行此操作,使用endptr 参数在任何成功转换后移动到下一个字符。如果愿意,您还可以使用面向字符的输入(例如getcharfgetc)手动执行数字识别和转换。

    鉴于您从 fgetssscanf 方法开始,以下继续。无论您使用sscanf 还是strtol,关键在于将下一次读取的开始提前到找到的每个整数之后的字符,例如

    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAXC 256
    
    int main (int argc, char **argv) {
    
        char buf[MAXC] = "";    /* buffer to hold MAXC chars at a time */
        int nval = 0;           /* total number of integers found */
        FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    
        if (!fp) {  /* validate file open for reading */
            fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
            return 1;
        }
    
        while (fgets (buf, MAXC, fp)) {
    
            char *p = buf;      /* pointer to line */
            int val,            /* int val parsed */
                nchars = 0;     /* number of chars read */
    
            /* while chars remain in buf and a valid conversion to int takes place
             * output the integer found and update p to point to the start of the
             * next digit.
             */
            while (*p) {
                if (sscanf (p, "%d%n", &val, &nchars) == 1) {
                    printf (" %d", val);
                    if (++nval % 10 == 0)     /* output 10 int per line */
                        putchar ('\n');
                }
                p += nchars;        /* move p nchars forward in buf */
    
                /* find next number in buf */
                for (; *p; p++) {
                    if (*p >= '0' && *p <= '9') /* positive value */
                        break;
                    if (*p == '-' && *(p+1) >= '0' && *(p+1) <= '9') /* negative */
                        break;
                }
            }
        }
        printf ("\n %d integers found.\n", nval);
    
        if (fp != stdin) fclose (fp);     /* close file if not stdin */
    
        return 0;
    }
    

    示例输入

    以下两个输入文件说明了仅从混合输入中挑选整数。您的文件:

    $ cat dat/blah.txt
     8 blah blah
     10 blah blah
     2 blah blah
     3 blah blah
    

    一个非常混乱的文件

    $ cat ../dat/10intmess.txt
    8572,;a -2213,;--a 6434,;
    a- 16330,;a
    
    - The Quick
    Brown%3034 Fox
    12346Jumps Over
    A
    4855,;*;Lazy 16985/,;a
    Dog.
    11250
    1495
    

    使用/输出示例

    在你的情况下:

    $ ./bin/fgets_sscanf_int_any_ex < dat/blah.txt
     8 10 2 3
     4 integers found.
    

    文件真的很乱:

    $ ./bin/fgets_sscanf_int_any_ex <dat/10intmess.txt
     8572 -2213 6434 16330 3034 12346 4855 16985 11250 1495
    
     10 integers found.
    

    查看一下,如果您有任何问题,请告诉我。

    【讨论】:

      【解决方案3】:

      “只读整数”的简单方法是在失败时使用fscanf(file_pointer, "%d", ...)fgetc()

      int x;
      int count;
      while ((count = fscanf(file_pointer, "%d", &x)) != EOF) {
        if (count == 1) { 
          // Use the `int` in some fashion (store them in an array)
          printf("Success, an int was read %d\n", x);
        } else {
          fgetc(file_pointer); // Quietly consume 1 non-numeric character
        }
      }
      

      我得到了存储第一个数字 8 的代码,但它停在那里。

      这是因为有问题的非数字输入仍保留在 FILE 流中。该文本需要以某种other 方式使用。再次调用 fscanf(instructionFile, "%d", &amp;num); 会导致同样的问题:fscanf() 失败,因为初始输入不是数字。


      注意:OP 的代码缺少 FILE 指针

      // fscanf(????, "%d %s %s", &num, string1, string2);    
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-02-10
        • 2023-04-09
        • 1970-01-01
        • 1970-01-01
        • 2019-05-12
        • 2018-10-25
        • 1970-01-01
        相关资源
        最近更新 更多