【问题标题】:How to skip a comment in c programming with using fopen如何使用 fopen 在 c 编程中跳过注释
【发布时间】:2019-10-07 03:07:46
【问题描述】:

当我使用fgets 时,我想忽略/跳过文本文件中的 cmets。

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

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

A 是我的第一个节点,B 是我的第二个节点,当 # 出现时,我想忽略其余的文本,直到下一行。我的新节点应该是 D 和 C 等。我只能在 fopen 函数中使用“r”。 我试过fgets,但它会逐行读取,fgetc 也无济于事。

    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);
....
}

【问题讨论】:

  • 我不清楚您是想跳过A B #Path between A and B. 行还是将该行更改为A B
  • 我只想阅读 A B 并在 # 出现时跳过该行
  • 关于; fscanf(file, "%40[0-9a-zA-Z]s", ch); 字母 's' 是 '%[..]' 中允许的输入字符的一部分,因此会被对 fscanf() 的调用消耗,因此对 fscanf() 的发布调用无效

标签: c fopen fgets fgetc feof


【解决方案1】:

您还可以使用strcspn 在一个简单的调用中修剪所有 cmets(如果不存在,则从缓冲区中修剪行尾)。您通常会从fgets() 读取的缓冲区中修剪行尾:

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

如果有评论,您可以简单地将"#" 字符添加到您的reject 列表和nul-terminate 中。这将减少删除以'#' 开头的 cmets 并将新格式化的行输出到:

    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;
}

输入文件示例

借用汤姆的示例文件:)

$ 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

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

【讨论】:

    【解决方案2】:

    方法名称也不同,但我对这个版本是否正确? 忽略我的肮脏方法 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;
    }
    

    【讨论】:

    • OT: about: printf("Error\n"); fprintf(stderr, "ERROR: No file input\n"); 当从 C 库函数返回错误指示时,应输出您的错误消息和系统认为发生错误的文本原因。建议perror( "fopen failed" );
    • 关于:#include &lt;iostream&gt; iostream 是 C++ 头文件,而不是 C 头文件,OP 将问题标记为 C 问题
    • while (!feof(file)) is always wrong——虽然这里几乎没问题。这是else if (x &lt; 0) break; 的非常古怪的缩进(和间距)。
    • 如果您认为某些答案有帮助,最好将其标记为已接受(在投票按钮下打勾);-) cplusplus.com/reference/cstdio/feof 我知道示例 linux 有一切不同或相反的东西,包括 -1 end的文件返回为无符号类型,在某些嵌入式环境中默认有符号字符等,但至少有时它应该根据该参考工作(也在 VS 2008 Express/W 7 中测试);-) 顺便说一句,有没有人严格使用oldschool "wild" C 除非有一个晦涩难懂的编译器(反正剩下的都是原始的)?
    【解决方案3】:

    以下建议的代码:

    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 );
    }
    

    【讨论】:

      猜你喜欢
      • 2013-08-24
      • 2012-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-19
      • 2015-03-07
      • 2021-12-01
      相关资源
      最近更新 更多