从 C 文件中删除注释

问题描述 投票:0回答:1

工作目的:学习如何使用标准C库的函数来处理文件

任务: 有一个包含 C 程序的文件。有必要删除其中的所有注释并将没有注释的代码写入新文件。

解释和实施特点:

  1. 程序文件可能会很大。因此,不能预先将整个文件读入数组。
  2. 注释可以是单行或多行。如果使用“反斜杠”字符“\”移动到下一行,单行注释也可以由多行组成。
  3. C语言中没有嵌套注释
  4. 不考虑字符串常量内的注释
  5. 文件不一定代表正确的C程序。例如,评论可能会在未关闭的情况下中断
  6. 允许出现一些新的空格和/或换行符来代替已删除的注释,并且允许不存在一些现有的非重要分隔符。
  7. 不允许删除带引号(双引号和单引号)的常量字符串中的数据。

输入输出数据: 源文件始终命名为 test.c 输出文件必须命名为 test.wc

我的代码:

#include <stdio.h>

#define TRUE 1
#define FALSE 0

typedef int BOOL;

int mygetc (FILE *in) {
        for (;;) {
                int c = getc(in);
                if (c == '\\') {
                        c = getc(in);
                        if (c == '\n')
                                continue;
                        if (c != EOF)
                                ungetc(c, in);
                        c = '\\';
                }
                return c;
        }
}

int skip_line_comment (FILE *in) {
        int c;
        while ((c = mygetc(in)) != '\n' && c != EOF)
                continue;
        return c;
}

int skip_block_comment (FILE *in) {
        int c;
        for (;;) {
                while ((c = mygetc(in)) != '*') {
                        if (c == EOF)
                                return c;
                }
                while ((c = mygetc(in)) == '*')
                        continue;
                if (c == EOF)
                        return c;
                if (c == '/')
                        return ' ';
        }
}

void removeComments (FILE *in, FILE *out) {
        int c;
        while ((c = mygetc(in)) != EOF) {
                if (c == '"' || c == '\'') {
                        int separator = c;
                        fputc(c, out);
                        while ((c = mygetc(in)) != separator && c != EOF) {
                                fputc(c, out);
                                if (c == '\\') {
                                        c = mygetc(in);
                                        if (c == EOF) break;
                                        fputc(c, out);
                                }
                        }
                } else if (c == '/') {
                        c = mygetc(in);
                        if (c == '/') c = skip_line_comment(in);
                        else if (c == '*') c = skip_block_comment(in);
                        else fputc('/', out);
                        
                }
                if (c == EOF) break;
                fputc(c, out);
        }
}

int main () {
        const char inName[20]  = "test.c";
        const char outName[20] = "test.wc";
        FILE *in;
        FILE *out;
  
        in  = fopen(inName, "r");
        out = fopen(outName, "w");
       
        removeComments(in, out);

        fclose(in);
        fclose(out);
  
        return 0;
}

.zip 包含测试: Google Disk

  1. 测试 1 - 正确
  2. 测试 2 - 正确
  3. 测试 3 - 第一行缺少“/”
  4. 测试 4 - 预期在一行中出现“* * *”,但在不同的行中得到 *
  5. 测试 5 - 正确
  6. 测试 6 - “”的问题,有一些额外的行,如“”“”“”“”\“”“\”,必须删除
  7. 测试 7 - 正确
  8. 测试 8 - 去掉多余的线
  9. 测试 9, 10 - / 和 \ 组合的问题
  10. 测试 11 - 正确
  11. 测试 12 - 正确
  12. 测试 13 - 正确
c file comments c99
1个回答
0
投票

这个问题有多个问题:

  1. 尚不清楚输出程序是否与源程序有细微的差别,例如

    • 行结尾(LF 或 CR/LF 对)
    • 非重要的初始和/或尾随空格
    • 空行
    • 抑制转义换行序列(
      \
      后跟行尾序列)
  2. 测试文件使用 DOS 行结束序列 (CR/LF) 进行编码,预期输出文件使用 unix 行结束 (LF) 和 DOS 行结束序列的不一致组合。该zip文件还包含macOS属性文件(在__MACOSX/目录中),表明它是在Mac上生成的,Mac使用unix行结尾,并且不会翻译以文本模式打开的文件的行结尾(

    "r"
    "w"
    )。预期的输出文件很可能是在 mac 或 unix 系统上从 DOS 源文件生成的,其中 DOS 行尾序列是从源文件中原样复制的,将
    '\n'
    输出替换为多行注释未翻译通过标准库将 CR/LF 序列转换为 CR/LF 序列,就像它们在遗留系统上一样。

  3. 测试文件包含许多不一致之处,例如缺少空格和换行符。问题陈述应该更精确,指定单行注释应替换为单个换行符,多行注释应替换为单个空格。

这使得编写能够精确产生预期输出的程序变得困难。

您的程序非常简单并且看起来正确,但会有一些限制和错误:

  • 如果在unix系统上编译,它无法识别CR/LF序列,因此它不会将CR/LF后面的

    \
    处理为转义换行符。这会阻止正确处理注释,其中
    //
    /*
    */
    序列被分成两行并带有转义换行符。

  • 程序不会将序列

    /"
    处理为
    /
    后跟字符串开头,因为
    "
    是由正文末尾的
    fputc(c, out)
    输出的,并且仅测试下一个字符的
     '
    "
    。同样的问题
    /'

  • 程序会抑制所有转义换行符,包括那些外部注释,这不是测试文件所期望的。

© www.soinside.com 2019 - 2024. All rights reserved.