【问题标题】:What is the fastest way to count lines and words in a text file in ANSI C?在 ANSI C 中计算文本文件中的行数和单词的最快方法是什么?
【发布时间】:2010-10-01 09:08:20
【问题描述】:

在纯 ANSI C 中计算文本文件中的行数和单词的最快方法是什么?

单词以空格或句点结尾。行由'\n' 终止。

This seems to be in C++.

【问题讨论】:

  • 如果您只是更改为 ANSI C 方式从文件中读取,您链接到的 C++ 解决方案应该直接转换为 C,不是吗?因此,据我所知,这使得问题本质上是“如何从 ANSI C 中读取文件?”
  • 定义“单词”和“行”非常好"Mc'Donalds" 是一个词吗? "RS232C""transli-\nneated" 呢?是否在前面的 word 示例中间换行了?
  • This。它大约有 800 行代码,但它高效且经过良好测试。
  • 根据你对“word”和“line”的定义,在一个包含3个空格、一个换行符、3个句点(总共7个字符)的文件中,有多少个单词和多少行?

标签: c text-files


【解决方案1】:
  • 读取文件
  • 遍历字符增加字符计数器
  • 检查空格/行尾是否增加字数计数器
  • 重复第二步和第三步直到EOF

【讨论】:

  • 这种方法在网上随处可见。
  • JMSA:是的,但它也是(几乎,除了缓冲)您链接到的 C++ 示例中使用的方法,所以听起来像您想要的。
【解决方案2】:

不妨看看 GNU wc 实用程序的源代码,因为该实用程序完全符合您的要求。

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

typedef unsigned long count_t;  /* Counter type */

/* Current file counters: chars, words, lines */
count_t ccount;
count_t wcount;
count_t lcount;

/* Totals counters: chars, words, lines */
count_t total_ccount = 0;
count_t total_wcount = 0;
count_t total_lcount = 0;

/* Print error message and exit with error status. If PERR is not 0,
   display current errno status. */
static void
error_print (int perr, char *fmt, va_list ap)
{
  vfprintf (stderr, fmt, ap);
  if (perr)
    perror (" ");
  else
    fprintf (stderr, "\n");
  exit (1);  
}

/* Print error message and exit with error status. */
static void
errf (char *fmt, ...)
{
  va_list ap;

  va_start (ap, fmt);
  error_print (0, fmt, ap);
  va_end (ap);
}

/* Print error message followed by errno status and exit
   with error code. */
static void
perrf (char *fmt, ...)
{
  va_list ap;

  va_start (ap, fmt);
  error_print (1, fmt, ap);
  va_end (ap);
}

/* Output counters for given file */
void
report (char *file, count_t ccount, count_t wcount, count_t lcount)
{
  printf ("%6lu %6lu %6lu %s\n", lcount, wcount, ccount, file);
}

/* Return true if C is a valid word constituent */
static int
isword (unsigned char c)
{
  return isalpha (c);
}

/* Increase character and, if necessary, line counters */
#define COUNT(c)       \
      ccount++;        \
      if ((c) == '\n') \
        lcount++;

/* Get next word from the input stream. Return 0 on end
   of file or error condition. Return 1 otherwise. */
int
getword (FILE *fp)
{
  int c;
  int word = 0;

  if (feof (fp))
    return 0;

  while ((c = getc (fp)) != EOF)
    {
      if (isword (c))
        {
          wcount++;
          break;
        }
      COUNT (c);
    }

  for (; c != EOF; c = getc (fp))
    {
      COUNT (c);
      if (!isword (c))
        break;
    }

  return c != EOF;
}

/* Process file FILE. */
void
counter (char *file)
{
  FILE *fp = fopen (file, "r");

  if (!fp)
    perrf ("cannot open file `%s'", file);

  ccount = wcount = lcount = 0;
  while (getword (fp))
    ;
  fclose (fp);

  report (file, ccount, wcount, lcount);
  total_ccount += ccount;
  total_wcount += wcount;
  total_lcount += lcount;
}

int
main (int argc, char **argv)
{
  int i;

  if (argc < 2)
    errf ("usage: wc FILE [FILE...]");

  for (i = 1; i < argc; i++)
    counter (argv[i]);

  if (argc > 2)
    report ("total", total_ccount, total_wcount, total_lcount);
  return 0;
}

发现于: http://www.gnu.org/software/cflow/manual/html_node/Source-of-wc-command.html

【讨论】:

【解决方案3】:

这是一个计算行数的明确答案(对字数的扩展是微不足道的,就像 OP 中链接的 C++ 版本一样)。这个版本是缓冲的。另一个答案建议首先阅读整个文件,这更简单,但下面更符合您的 C++ 示例所做的。

#include <stdio.h>
#include <string.h>

#define BUFSIZE 1024

int main(int argc, char** argv)
{
  int newlines = 0;
  char buf[BUFSIZE];
  FILE* file;

  if (argc != 2)
    return 1;

  file = fopen(argv[1], "r");
  while (fgets(buf, BUFSIZE, file))
  {
    if (!(strlen(buf) == BUFSIZE-1 && buf[BUFSIZE-2] != '\n'))
      newlines++;
  }

  printf("Number of lines in %s: %d\n", argv[1], newlines);

  return 0;
}

可以调整 BUFSIZE 宏以最大限度地提高性能(因为您说您想要 最快 方式)。 1024只是一个猜测。另一种可能是读取文件内存映射,但我没有尝试,因为 mmap 不是 ANSI C。

【讨论】:

  • 这不处理最后一行没有以行分隔符终止的情况。为此,您需要一个状态机。它也不容易扩展到计算单词,因为这也需要状态机。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-14
  • 1970-01-01
  • 2012-02-16
  • 2011-08-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多