使用C将行号添加到文件中每一行的开头

时间:2019-04-29 22:44:34

标签: c

我正在做一个作业,该作业读取一个文本文件,并在每行的开头添加行号。

我对编码还很陌生,所以如果这是一个简单的任务,对不起。我编写的代码将为我提供输出,告诉我文件中有多少行,但是我无法弄清楚如何实际地对行进行编号并将其显示给我。

//lineNumber = 1;
//Open the file
//While ((c = read a character) is not EOF)
//    If (c is \n)
//        Print "lineNumber", then increment it
//    Print c
//End while
//Close the file
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main() {

    int ln = 1;
    char c;
    FILE *fp = fopen("text.txt", "r");

    while((c=getc(fp))!=EOF) {

        if (c=='\n'){
            ln++;
        }
    }
    printf("lines num: %d",c);
    fclose(fp);
    //return 0;
}

示例输入:

This is a text file
This text file has words in it.

示例输出:

000001 This is a text file
000002 This text file has words in it.

4 个答案:

答案 0 :(得分:3)

您有一个程序可以计算文件中的行数,您需要更改它,以便无需在末尾显示计数 回显文件内容

(例如,在每个getc()之后使用putchar(c);)和

每次您看到\n(以及文件的开头) 您需要打印一个带有前导零的数字,然后打印一个空格。 printf("%06d ",ln) ;可能就是您想要的。

答案 1 :(得分:1)

您有很多小问题要解决。首先,除非您使用的是不合格的编译器,否则main的合格声明为int main (void)int main (int argc, char **argv)(将看到用等效的char *argv[]编写)。请参阅:C11 Standard §5.1.2.2.1 Program startup p1 (draft n1570)。另请参阅:What should main() return in C and C++?

接下来,c必须为int类型,而不是char以匹配EOF,例如

    int c, last = 0; /* c must be type int, not char to match EOF */

不要硬编码文件名或使用魔术数字。将文件名作为参数传递给main()或在程序中提示输入文件名。您可以方便地使用三元运算符通过stdin来获取文件名以从default打开或读取,如下所示:

    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

最后,对于代码,由于要为每行添加行号前缀 ,因此必须输出第一行的行号之前,为该行输出字符该行(每个后续行都相同)。您可以简单地通过首先输出数字来做到这一点(使用带有修饰符"%06zu "的{​​{1}}转换说明符输出前导零,并将 field-width '0'输出到前导零。匹配显示的格式)。还要注意,6计数器的类型已从ln更改为int,这是C语言中推荐的计数器类型(行数不能为负)。

将其与size_t字符一起使用以允许在输出字符之前检查last,可以执行以下操作:

'\n'

注意:退出循环后对#include <stdio.h> int main (int argc, char **argv) { int c, last = 0; /* c must be type int, not char to match EOF */ size_t ln = 1; /* use size_t for counters */ /* use filename provided as 1st argument (stdin by default) */ FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin; if (!fp) { /* validate file open for reading */ perror ("file open failed"); return 1; } printf ("%06zu ", ln++); /* output line 1 number */ while ((c = getc(fp)) != EOF) { /* read each character */ if (last) /* test if last set */ putchar (last); /* output all characters */ if (last == '\n') /* test if last is newline */ printf ("%06zu ", ln++); /* output next line number */ last = c; /* set last to c */ } putchar (last); /* output final character */ if (last != '\n') /* check POSIX eof */ putchar('\n'); /* tidy up with newline */ if (fp != stdin) /* close file if not stdin */ fclose (fp); return 0; } 的检查将检查是否存在以最后一行结尾的POSIX行,如果没有,则应手动输出{{ 1}},以便您的程序符合POSIX)

示例输入文件

if (last != '\n')

使用/输出示例

'\n'

仔细检查一下,如果还有其他问题,请告诉我。

也请注意::如果您的编译器不支持$ cat ../dat/captnjack.txt This is a tale Of Captain Jack Sparrow A Pirate So Brave On the Seven Seas. 的{​​{1}}转换说明符,请删除$ ./bin/linenos ../dat/captnjack_noeol.txt 000001 This is a tale 000002 Of Captain Jack Sparrow 000003 A Pirate So Brave 000004 On the Seven Seas. 并输出为无符号值-VS10或更早的版本不支持zu

答案 2 :(得分:0)

要对此行进行编号或更改文件的任何部分,最好将文件作为字符串加载到内存中,操纵该字符串(在这种情况下,添加行号),然后创建一个空白新文件。将修改后的字符串复制到新文件中,然后将其重命名为旧文件的路径,以将其覆盖。

/* fp: File whose lines are to be numbered 
   pathOld: Its path */
void giveLineNos(FILE *fp, const char *pathOld)
{
    char line[MAXLINE]; /* line that is read in */
    char numbered[MAXLINE + 8]; /* line that will include its number */
    int i;

    char tempName[L_tmpnam];
    tmpnam(tempName);  /* generate filename guaranteed to be unique */

    FILE *fpNumbered = fopen(tempName, "w"); /* create temporary file onto 
                              which we will write; error checking omitted */

    for (i = 0; fgets(line, MAXLINE, fp) != NULL; ++i) {
        /* write out the line number followed by its contents */
        snprintf(numbered, MAXLINE + 8, "%d: ", i + 1);
        strcat(numbered, line);

        fputs(numbered, fpNumbered); /* save line to file */
    }

    rename(tempName, pathOld);  /* rename the temporary file to that of 
                                    the old one, thereby overwriting it */
    fclose(fpNumbered);
    fclose(fp);
}

如果您只想打印编号的行而甚至不触摸文件,则可以用对fputs的调用来替换上面代码中的printf语句:

/* fputs(numbered, fpNumbered); */ printf("%s", numbered);

(在%s之后放置换行是错误的,因为fgets已经在line缓冲区中放入了换行,然后将其转移到numbered中。)

还要注意,您的main是非标准的。使用int作为返回类型,而不是void

答案 3 :(得分:0)

我建议不要在每个'\n'处增加行数,而每次在'\n'之后读取一个字符时都应增加行数。这也是代码应打印行号的时候

unsigned long ln = 0;
int prev = '\n';
int c;  // Use int here, not char
while((c=getc(fp))!=EOF) {
  if (prev == '\n'){
    printf("%06lu ", ++ln);
  }
  putchar(c);
  prev = c;
}
if (prev != '\n') {
  putchar('\n');  // print a \n for input that lacks a final \n
}
printf("lines num: %lu\n", ln);

请注意,当行数为0(无数据)且输入不以'\n'结尾时,上述方法效果很好。

使用fgets()的常见缺点是1)当行长超过输入缓冲区时,需要特殊处理2)当输入意外包含 null字符时,会冒犯热带字符串处理。 getchar()没有这些问题。