【问题标题】:counting the number of strings in a text file containing numbers as well计算包含数字的文本文件中的字符串数
【发布时间】:2016-06-29 05:53:21
【问题描述】:

我只想计算文本文件中字符串的数量,包括数字。但是下面的代码甚至将文件中的数字都计为字符串。我该如何解决这个问题?

int count;
char *temp;
FILE *fp;

 fp = fopen("multiplexyz.txt" ,"r" );

 while(fscanf(fp,"%s",temp) != EOF )
 {
     count++;
 }

 printf("%d ",count);
 return 0;

}

【问题讨论】:

  • 你能举个例子吗,输入文件,实际输出和预期输出。
  • 字符串是一组单词。因此,如果您的文件只有 1 个单词,它是纯数字 {3422},例如 this is nub1234 3422 hello rock,那么您期望的计数是多少?
  • 我正在尝试计算纯字符串的数量。在我的输入中没有混合字母和数字。对于给定的输入,预期的输出:4 { this,is,hello,rock}

标签: c string file


【解决方案1】:

嗯,首先,使用temp 指针而没有后备存储会给你带来痛苦。

我建议,作为开始,使用 char temp[1000] 之类的东西,请记住,如果您的单词长度超过一千个左右字符,这仍然有点冒险(这是一个不同 问题到您要询问的问题,所以我会提到它,但不会花费 太多 太多时间来修复它)。

其次,您似乎想用数字计算单词(如alpha7pi/2)。如果是这种情况,您只需在读取“单词”后检查temp,并仅在匹配“非数字”模式时增加count

如果单词仅由数字组成,那可以简单到不递增,或者如果你想处理小数、指数格式等,它可能会很复杂。

但底线保持不变:

while(fscanf(fp,"%s",temp) != EOF )
{
    if (! isANumber(temp))
        count++;
}

具有isANumber 的合适定义。例如,仅对于无符号整数,这样的事情将是一个好的开始:

int isANumber (char *str) {
    // Empty string is not a number.

    if (*str == '\0')
        return 0;

    // Check every character.

    while (*str != '\0') {
        // If non-digit, it's not a number.

        if (! isdigit (*str))
            return 0;
        str++;
    }

    // If all characters were digits, it was a number.

    return 1;
}

对于更复杂的检查,您可以使用 C 中的 strto* 调用,为它们提供 temp 缓冲区并确保您使用 endptr 方法来确保扫描整个字符串。在我的脑海中,所以没有很好测试过,这会是这样的:

int isANumber (char *str) {
    // Empty string is not a number.

    if (*str == '\0')
        return 0;

    // Use strtod to get a double.

    char *endPtr;
    long double d = strtold (str, &endPtr);

    // Characters unconsumed, not number (things like 42b).

    if (*endPtr != '\0')
        return 0;

    // Was a long double, so number.

    return 1;
}

您唯一需要注意的是,NaN+Inf 等某些字符串被 strtold 视为数字,因此您可能需要对此进行额外检查。

【讨论】:

    【解决方案2】:

    在您的 while 循环中,循环遍历字符串以检查其中的任何字符是否为数字。比如:

    while(*temp != '\0'){
           if(isnumber(*temp))
               break;
    }
    

    [不要复制完全相同的代码]

    【讨论】:

      【解决方案3】:

      我发现strpbrk 是在haystack 中搜索多个needles 的最有用的功能之一。您的 needles 集是数字字符 "0123456789",如果从您的文件读取的行中存在这些字符,则将计为一行。我也更喜欢 POSIX getline 的行数,以正确处理最后一行具有非 POSIX 行结尾的文件(fgetswc -l 省略最后一行的文本(和计数),如果它不包含 POSIX 行尾 ('\n')。也就是说,一个小函数在行中搜索包含在作为参数传递的 trm 中的字符可以写成:

      /** open and read each line in 'fn' returning the number of lines
       *  continaing any of the characters in 'trm'.
       */
      size_t nlines (char *fn, char *trm)
      {
          if (!fn) return 0;
      
          size_t lines = 0, n = 0;
          char *buf = NULL;
          FILE *fp = fopen (fn, "r");
      
          if (!fp) return 0;
      
          while (getline (&buf, &n, fp) != -1)
              if (strpbrk (buf, trm))
                  lines++;
      
          fclose (fp);
          free (buf);
      
          return lines;
      }
      

      只需传递感兴趣的文件名和要在每一行中搜索的术语。一个简短的测试代码,默认术语为"0123456789",将文件名作为第一个参数,术语作为第二个参数,可以编写如下:

      #include <stdio.h>      /* printf */
      #include <stdlib.h>     /* free   */
      #include <string.h>     /* strlen, strrchr */
      
      size_t nlines (char *fn, char *trm);
      
      int main (int argc, char **argv) {
      
          char *fn   = argc > 1 ? argv[1] : NULL;
          char *srch = argc > 2 ? argv[2] : "0123456789";
          if (!fn) return 1;
      
          printf ("%zu %s\n", nlines (fn, srch), fn);
      
          return 0;
      }
      
      /** open and read each line in 'fn' returning the number of lines
       *  continaing any of the characters in 'trm'.
       */
      size_t nlines (char *fn, char *trm)
      {
          if (!fn) return 0;
      
          size_t lines = 0, n = 0;
          char *buf = NULL;
          FILE *fp = fopen (fn, "r");
      
          if (!fp) return 0;
      
          while (getline (&buf, &n, fp) != -1)
              if (strpbrk (buf, trm))
                  lines++;
      
          fclose (fp);
          free (buf);
      
          return lines;
      }
      

      试一试,看看这是否是您所期望的,如果不是,请告诉我,我很乐意为您提供进一步的帮助。

      输入文件示例

      $ cat dat/linewno.txt
      The quick brown fox
      jumps over 3 lazy dogs
      who sleep in the sun
      with a temp of 101
      

      使用/输出示例

      $ ./bin/getline_nlines_nums dat/linewno.txt
      2 dat/linewno.txt
      
      $ wc -l dat/linewno.txt
      4 dat/linewno.txt
      

      【讨论】:

      • wc 关于行的行为可以说正确,如果您将一行定义为零个或多个以换行符结尾的字符(即完整的行)。此外,考虑您有两个这样的文件ab 的情况。如果您认为最后一个非换行行是实际行,则单个文件的行数总和(wc -l &lt;a 加上wc -l &lt;b)不等于连接在一起的文件的行数(cat a b | wc -l )。不是说你的方式是对的错,只是说它是微妙的。无论如何,它不会影响您回答的核心。
      • 而且,由于我很好奇,我查看了手册页以了解其意图。它非常明确地声明了-lprint the newline counts。因此,无论您是否同意这种行为,它都完全按照指定的方式工作。也许我们应该为--lines-including-final-possibly-non-terminated-one 提出功能请求:-)
      • 是的,wc -l 如何报告行是一个奇怪的选择。我想这就是为什么我们有一个 POSIX 行结尾的定义。一个同样有趣的启示是为什么while (fgets (...))while (getline (...) != -1) 根据 POSIX 行结尾报告不同的行数。很明显它会打你的脸,但这并不能阻止你在灯泡亮起之前的几分钟挠头(至少对我来说)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-09-23
      • 1970-01-01
      • 2013-03-29
      • 1970-01-01
      • 2014-02-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多