使用 C 计算 ASCII 文件中的行数

Count lines in ASCII file using C

我想计算 ASCII 文本文件中的行数。 我认为最好的方法是计算文件中的换行符:

for (int c = fgetc(fp); c != EOF; c = fgetc(fp)) {  /* Count word line endings. */
    if (c == '\n') ++lines;
}

但是,我不确定这是否会解释所有 MS Windows 和 Linux 的最后一行。也就是说,如果我的文本文件如下完成,没有明确的换行符,是否有一个编码在那里还是我应该在 for 循环之后添加一个额外的 ++lines;

cat
dog

那么如果文件末尾一个明确的换行符呢?还是我只需要通过跟踪先前读取的值来测试这种情况?

如果没有换行符,则不会生成。 C 准确地告诉你那里有什么。

这个怎么样:

为自己创建一个标志,以跟踪在 c=='\n' 时重置的 \n 之后的任何非 \n 字符。 在 EOF 之后,检查标志是否为真,如果是则递增。

bool more_chars = false;
for (int c = fgetc(fp); c != EOF; c = fgetc(fp)) {  /* Count word line endings. */
            if (c == '\n') {
              more_chars = false;
              ++words;
            } else more_chars = true;
 }
 if(more_chars) words++;

如果您要使用此方法,您始终可以保留一个单独的计数器来计算您所在行的字母数。如果末尾的计数大于 1,那么您就知道最后一行有未计算在内的内容。

int letters = 0

for (int c = fgetc(fp); c != EOF; c = fgetc(fp)) {  /* Count word line endings. */
    letters++; // Increase count on character

    if (c == '\n')
    {
        ++words;
        letters = 0; // Set back to 0 after new line
    }
}

if (letters > 0)
{
    ++words;
}

文本文件总是应该以换行结束。没有处理不符合规范的文件的规范方法。

以下是某些工具选择处理最后换行后字符的方式:

  • wc 不把它算作一行(所以你有很好的优先级)
  • Vim 将文件标记为 [noeol],并在没有尾随换行的情况下保存文件
  • GNU sed 将文件视为有最后一个换行符
  • shread 错误退出,但 returns 数据

由于行为几乎没有定义,您可以做任何对您方便或有用的事情。

您的担心是真实的,文件中的最后一行可能缺少最后的行尾标记。行尾标记是 Linux 中的单个 '\n',Windows 中的 CR LF 对,C 运行时会自动将其转换为 '\n'.

您可以简化代码并以这种方式处理最后一行缺少换行符的特殊情况:

int c, last = '\n', lines = 0;

while ((c = getc(fp)) != EOF) {  /* Count word line endings. */
    if (c == '\n')
        lines += 1;
    last = c;
}
if (last != '\n')
    lines += 1;

由于您关心速度,因此使用 getc 而不是 fgetc 将有助于在平台上将其定义为直接处理流结构并调用函数仅重新填充缓冲区,每 BUFSIZ 个字符左右,除非流是无缓冲的。

Windows 和 UNIX/Linux 风格的换行符在这里没有区别。在任一系统上,文本文件在最后一行的末尾可能有也可能没有换行符。

如果您总是在行数中加 1,当末尾 一个换行符(即文件 "foo\n" 将算作有两行:"foo""")。这可能是一个完全合理的解决方案,具体取决于您要如何定义一条线。

"line" 的另一个定义是它总是以换行符结尾,即文件 "foo\nbar" 根据这个定义只有一行 ("foo")。 wc.

使用了这个定义

当然,您可以跟踪换行符是否是文件中的最后一个字符,如果不是,则只在计数中加 1。然后 "line" 将被定义为以换行符结尾或在文件末尾非空,这对我来说听起来很复杂。

首先,最后一行的末尾不会有任何隐式编码的换行符。出现换行符的唯一方法是生成文件的软件或人员将其放在那里。然而,将它放在那里通常被认为是一种好的做法。

您应该将什么报告为行数的最终答案取决于您需要为软件或将使用此行数的人员遵循的约定,以及您可以假设的行为输入源也是如此。

大多数命令行工具将以换行符终止其输出。在这种情况下,明智的答案可能是将换行符数报告为实际行数。

另一方面,当文本编辑器显示文件时,您会看到页边空白处的行号(如果支持)包含最后一行的编号,无论它是否为空。这部分是为了告诉用户那里有一个空行,但是如果你想计算页边空白中显示的行数,它是文件中换行符数的一加。对于一些编码人员来说,通常不使用换行符终止他们的最后一行(有时是因为草率),所以在这种情况下,这个约定实际上是正确的答案。

我不确定任何其他约定是否有意义。例如,如果您选择不计算最后一行,除非它是非空的,那么什么才算是非空?文件在换行后结束?如果该行有空格怎么办?如果文件末尾有几个空行怎么办?