如何使用 fopen 在 c 编程中跳过注释

How to skip a comment in c programming with using fopen

提问人:Stefan Andersson 提问时间:5/21/2019 最后编辑:Stefan Andersson 更新时间:5/21/2019 访问量:1787

问:

我想在使用 .fgets

问题是,只有当一行中的第一个字符以 # 开头时,我才能跳过注释。注释从我的文本文件开始。但是我有一些不是一行的第一个字符,就像这样;##file.txt

#Paths
A B #Path between A and B.
D C #Path between C and D.

A 是我的第一个节点,B 是我的第二个节点,当 # 出现时,我想忽略其余的文本,直到下一行。我的新节点应该是 D 和 C 等。我只能在 fopen 函数中使用“r”。 我试过了,但它一行一行地阅读,也没有帮助。fgetsfgetc

    bool ignore_comments(const char *s)
    {
        int i = 0;
        while (s[i] && isspace(s[i])) i++;
        return (i >= 0 && s[i] == '#');
    }
    FILE *file;
    char ch[BUFSIZE];
    file = fopen("e.txt", "r");
    if (file == NULL) {
        printf("Error\n");
        fprintf(stderr, "ERROR: No file input\n");
        exit(EXIT_FAILURE);
    }
    while(fgets(ch, BUFSIZE, file) != NULL)
    {
              if (line_is_comment(ch)) {
                        // Ignore comment lines.
                        continue;
                printf("%c",*ch);
                }
     fscanf(file, "%40[0-9a-zA-Z]s", ch);
....
}
C fopen fgets fgetc feof

评论

0赞 Support Ukraine 5/21/2019
我不清楚你是想跳过这一行还是想把那一行改成只是?A B #Path between A and B.A B
0赞 Stefan Andersson 5/21/2019
我只想读 A B 并在 # 出现时跳过该行
0赞 user3629249 5/21/2019
关于; 字母 's' 是 '%[..]' 中允许的输入字符的一部分,因此会被调用 使用,因此发布的调用无效fscanf(file, "%40[0-9a-zA-Z]s", ch);fscanf()fscanf()

答:

0赞 Jan 5/21/2019 #1

方法名称也不同,但是我对这个版本是对的吗? 忽略我的肮脏方法line_is_comment - 从第一个版本开始,除非你想玩;-)

扩展测试输入:

#Paths
A B #Path between A and B.
D C #Path between C and D.
E F
G H

输出:

 rest of line read
AB rest of line read
DC rest of line read
EF rest of line read
GH rest of line read
#include <stdio.h>

bool line_is_comment(const char *s)
{
    char *commentPos = const_cast<char*>(strchr(s, '#'));
    if(commentPos != NULL) {
        *commentPos = 0; // cut-off chars after comment
        //return true; // or false then to accept the line
        return commentPos == s;
    }
    return false;
}

#define BUFSIZE 50

int main()
{
    FILE *file;
    char ch[BUFSIZE];
    file = fopen("e.txt", "r");
    if (file == NULL) {
        printf("Error\n");
        fprintf(stderr, "ERROR: No file input\n");
        exit(EXIT_FAILURE);
    }
    int x;
    while(!feof(file)) {
        x = fscanf(file, "%40[0-9a-zA-Z]s", ch);
        if(x == 0) {
            ch[0] = fgetc(file);
            if(ch[0] == '#' || ch[0] == '\n') {
                if(ch[0] != '\n') fgets(ch, BUFSIZE, file);
                printf(" rest of line read\n");
            }
        } else if(x<0) break;
        else {
                 printf("%c",*ch); // continue with ... undisclosed part here
            }
    }

    return 0;
}

评论

1赞 user3629249 5/21/2019
while(!feof(file)) 总是错的
0赞 user3629249 5/21/2019
OT:关于:当从 C 库函数返回错误指示时,应同时输出错误消息和系统认为发生错误的文本原因。建议printf("Error\n"); fprintf(stderr, "ERROR: No file input\n");perror( "fopen failed" );
1赞 user3629249 5/21/2019
关于:是 C++ 头文件,而不是 C 头文件,OP 将问题标记为 C 问题#include <iostream>iostream
0赞 Jonathan Leffler 5/21/2019
See while (!feof(file)) 总是错的——尽管这里它几乎没问题。这是非常古怪的缩进(和间距)。else if (x < 0) break;
0赞 Jan 5/21/2019
如果您认为有帮助,最好将一些答案标记为已接受(在投票按钮下打勾);-)cplusplus.com/reference/cstdio/feof我知道示例 linux 具有不同或相反的所有内容,包括作为无符号类型返回的文件末尾、某些嵌入式环境中的默认带符号字符等,但至少有时它应该根据该参考工作(也在 VS 2008 Express/W 7 中进行了测试);-)顺便说一句,有没有人使用严格的老派“野生”C,除非有一个晦涩难懂的编译器(无论如何,其余的都来自原始编译器)?
0赞 user3629249 5/21/2019 #2

建议的代码如下:

  1. 执行所需的功能
  2. 干净利落地编译
  3. 正确检查错误
  4. 此答案使用基于“InComment”的状态机

现在,建议的代码:

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

int main( void )
{
    int InComment = 0;

    FILE *fp = fopen( "file.txt", "r" );
    if( !fp )
    {
        perror( "fopen to read -file.txt- failed" );
        exit( EXIT_FAILURE );
    }

    int ch;

    while( (ch = fgetc(fp)) != EOF )
    {
        if( ch == '#' )
        {
            InComment = 1;
        }

        else if( ch == '\n' )
        {
            InComment = 0;
            fputc( ch, stdout );
        }

        else if( !InComment )
        {
            fputc( ch, stdout );
        }
    }
    fclose( fp );
}
0赞 David C. Rankin 5/21/2019 #3

您还可以使用“在单个简单调用中修剪所有注释(如果不存在,则从缓冲区中修剪行尾)。通常使用以下命令从缓冲区中剪裁行尾:strcspnfgets()

        ch[strcspn (ch, "\r\n")] = 0;  /* trim line-ending */

您可以简单地将该字符添加到您的拒绝列表中,如果存在评论,则在那里终止。这将减少删除以新格式行开头的注释并将其输出到以下内容的完整任务:"#"'#'

    while (fgets (ch, BUFSIZE, fp)) {   /* read every line */
        ch[strcspn (ch, "#\r\n")] = 0;  /* trim comment or line-ending */
        puts (ch);                      /* output line w/o comment */
    }

一个简短的例子,将文件作为程序的第一个参数读取(如果没有给出参数,则默认从读取),您可以执行以下操作:stdin

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

#define BUFSIZE 1024    /* if you need a constant, #define one (or more) */

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

    char ch[BUFSIZE];
    /* 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;
    }

    while (fgets (ch, BUFSIZE, fp)) {   /* read every line */
        ch[strcspn (ch, "#\r\n")] = 0;  /* trim comment or line-ending */
        puts (ch);                      /* output line w/o comment */
    }

    if (fp != stdin) fclose (fp);       /* close file if not stdin */

    return 0;
}

示例输入文件

借用 Tom 的示例文件:)

$ cat dat/comments_file.txt
#Paths
A B #Path between A and B.
D C #Path between C and D.
E F
G H

示例使用/输出

$ ./bin/comments_remove <dat/comments_file.txt

A B
D C
E F
G H

仔细查看,如果您还有其他问题,请告诉我。