【问题标题】:Remove comments from C program从 C 程序中删除注释
【发布时间】:2014-08-27 12:15:48
【问题描述】:

以下是我从 C 程序中删除 cmets 的代码。但是注释行不会被删除。它会删除/**/,但不会删除此分隔符之间的句子。

#include <stdio.h>

main(int argc, char *argv[]) {
    FILE *fp, *ft;
    char ch;
    if (argc < 3) {
        printf("No file name given");
    }
    fp = fopen(argv[1], "r");
    ft = fopen(argv[2], "w");
    if (fp == NULL)
        printf("Opening error");
    if (ft == NULL)
        printf("Opening error");
    while (1) {
        ch = fgetc(fp);
        if (ch == EOF)
            break;
        if (ch == '/') {
            ch = fgetc(fp);
            if (ch == '*') {
                putc(' ', ft);
            }
        } else if (ch == '*') {
            ch = fgetc(fp);
            if (ch == '/') {
                putc(' ', ft);
            }
        } else {
            putc(ch, ft);
        }
    }
    fclose(fp);
    fclose(ft); 
}

请帮我删除评论行。

【问题讨论】:

  • 为什么你认为这会起作用?为什么不在/* 之后的调试器中单步执行。然后问问自己,我要怎么做才能跳过所有字符直到*/
  • @Muskaan:您可以通过单击其分数下方的灰色复选标记来接受其中一个答案,并为那些对您有帮助的人投票。

标签: c comments


【解决方案1】:

您最后的 else 部分是编写所有不是 '/''*' 的字符。 我在下面更改了您的代码。 *******附加行*********显示更改的部分。试试看告诉我??祝你好运...

#include<stdio.h>

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

   FILE *fp,*ft;
   char ch;
   int flag=0;   //**********************additional line********

   if(argc<3)
   {
        printf("No file name given");
   }
   fp=fopen(argv[1],"r");
   ft=fopen(argv[2],"w");
   if(fp==NULL)
        printf("Opening error");
   if(ft==NULL)
        printf("Opening error");
   while(1)
   {
        ch=fgetc(fp);
        if(ch==EOF)
                break;
        if(ch=='/')
        {
                ch=fgetc(fp);
                if(ch=='*')
                {
                        flag=1; //**********************additional line********
                        putc(' ',ft);
                }
        }
        else if (ch=='*')
        {
                ch=fgetc(fp);
                if(ch=='/')
                {
                        flag=0;//**********************additional line********
                        putc(' ',ft);
                }
        }
        if(flag==0)   //**********************additional line********
        {
                putc(ch,ft);
        }
   }

   fclose(fp);
   fclose(ft); 


}

【讨论】:

  • 请注意,我把最后一个else语句改成了if语句。
【解决方案2】:

您的代码正确识别注释开始序列“/”和注释结束序列“/”并删除它们,但不删除它们之间的内容(例如应该使用标志)

/*
 *   flag = 1 if comment detected
 *   flag = 0 otherwise            
 */

if (flag == 0)
  {
    putc (ch, ft);
  }

如果您保持代码原样,它将删除所有“/”,不仅在注释中,而且在文件中的任何位置。我至少能想到一个不好的后果(当调用诸如&lt;sys/time.h&gt;&lt;sys/stat.h&gt;&lt;netinet/in.h&gt; 等标头时)。

由于注释的开始和结束序列是两个字符宽,我建议您使用 2 个“光标”来读取 fp,就好像每个循环读取 2 个字符一样。下面是一个示例(尽管它有效,但出于简单和可读性的原因,它不处理边缘情况,例如 EOF 之前的非关闭注释,或关闭注释序列之后的 EOF)。

#include <stdio.h>

int
main (int argc, char *argv[])
{
  FILE *fp, *ft;
  char ch, nextc;
  if (argc < 3)
   {
      printf ("No file name given");
   }
  fp = fopen (argv[1], "r");
  ft = fopen (argv[2], "w");
  if (fp == NULL)
    printf ("Opening error");
  if (ft == NULL)
    printf ("Opening error");
  nextc = fgetc (fp);
  while (nextc != EOF)
    {
      ch = nextc;
      nextc = fgetc (fp);

      if ((ch == '/') && (nextc == '*')) 
        {
          nextc = fgetc (fp);
          while ((ch != '*') && (nextc != '/')) /* unroll until the end of comment*/
            {
              ch = nextc;
              nextc = fgetc (fp);
            }
          ch = fgetc (fp);
          nextc = fgetc (fp);
        }

      putc (ch, ft);
    }
  fclose (fp);
  fclose (ft);
  return 0;
}

希望这会有所帮助。

【讨论】:

    【解决方案3】:

    只需更改上面代码中的行 while ((ch != '*') && (nextc != '/'))

    while (!((ch == '*') && (nextc == '/')))

    【讨论】:

    • 您可以通过在代码前面的一行放置四个空格或选择并单击编辑框上方的代码按钮,使您的代码出现在代码块中。您还需要在代码和文本之间有一个空行。
    【解决方案4】:

    对于这个问题,大多数答案只处理多行注释 (/..../),但也可能有单行 (//....) 行注释。 所以为了处理单行注释,krouis 的代码中有轻微的修改。

    #include <stdio.h>
    
    int main (int argc, char *argv[])
    {
      FILE *fp, *ft;
      char ch, nextc;
      if (argc < 3)
      {
           printf ("No file name given");
      }
      fp = fopen (argv[1], "r");
      ft = fopen (argv[2], "w");
      if (fp == NULL)
           printf ("Opening error");
      if (ft == NULL)
           printf ("Opening error");
      nextc = fgetc (fp);
      while (nextc != EOF)
      {
         ch = nextc;
         nextc = fgetc (fp);
    
         if ((ch == '/') && (nextc == '*')) 
         {
            ch = fgetc (fp);
            nextc = fgetc (fp);
            while (!((ch == '*') && (nextc == '/'))) /* unroll until the end of comment*/
            {
              ch = nextc;
              nextc = fgetc (fp);
            }
            nextc = fgetc (fp);
            continue;
         }else if((ch=='/') && (nextc == '/')) // block to handle single line comment.
         {
            nextc = fgetc (fp);
            while (!(nextc == '\n')){
               nextc = fgetc (fp);
            }
           nextc = fgetc (fp);
           continue;
         }
         putc (ch, ft);
       }
      fclose (fp);
      fclose (ft);
      return 0;
     }
    

    【讨论】:

      【解决方案5】:

      您的代码中有多个问题:

      • 不应省略main 的返回类型。隐式 int 已过时,C 标准不再允许。原型应该是int main(int argc, char *argv[])
      • 如果命令行参数没有传递给程序,它应该在打印错误消息后退出,应该输出到stderr而不是stdout
      • 如果输入文件无法打开,程序不应创建输出文件。
      • 如果任一fopen 失败,程序应该停止而不是进入未定义行为的领域。
      • ch 必须具有类型 int 而不是 char 才能使测试 (ch == EOF) 正常运行。
      • 您正确识别序列/**/ 并将它们替换为单个,但它实际上会删除所有其他出现的/* 以及后续字符并且您没有任何跳过中间字符的规定。
      • main 应该返回 0

      另请注意,如果序列 /**/ 出现在单行 cmets 或字符串或字符常量中,您的方法可能无法正确识别 cmets。此外,您还应该处理转义的换行符(\ 在行尾),因为这些换行符可能出现在/* 之间,从而隐藏了注释的开始或结束序列。

      这是处理这些情况的修改版本:

      #include <stdio.h>
      
      /* read the next byte from the C source file, handing escaped newlines */
      int getcpp(FILE *fp) {
          int ch;
          while ((ch = getc(fp)) == '\\') {
              if ((ch = getc(fp)) != '\n') {
                  ungetc(ch, fp);
                  return '\\';
              }
          }
          return ch;
      }
      
      /* read and write character and string constants */
      int skipstr(int cch, FILE *fp, FILE *ft) {
          int ch;
          putc(cch, ft);
          while ((ch = getcpp(fp)) != EOF) {
              putc(ch, ft);
              if (ch == cch)
                  return 0;
              if (ch == '\\') {
                  if ((ch = getcpp(fp)) == EOF)
                      return EOF;
                  putc(ch, ft);
              }
          }
          return EOF;
      }
      
      int main(int argc, char *argv[]) {
          FILE *fp, *ft;
          int ch;
      
          if (argc < 3) {
              fprintf(stderr, "Missing arguments. Need input and output filenames\n");
              return 1;
          }
          if ((fp = fopen(argv[1], "r")) == NULL) {
              fprintf(stderr, "Cannot open input file %s\n", argv[1]);
              return 1;
          }
          if ((ft = fopen(argv[2], "w")) == NULL) {
              fprintf(stderr, "Cannot open output file %s\n", argv[2]);
              return 1;
          }
          while ((ch = getcpp(fp)) != EOF) {
              if (ch == '\'' || ch == '"') {
                  if (skipstr(ch, fp, ft)) {
                      fprintf(stderr, "unterminated string or character constant\n");
                      break;
                  }
                  continue;
              }
              if (ch == '/') {
                  if ((ch = getcpp(fp)) == '*') {
                      /* multi-line comment */
                      int lastc = 0;
                      while ((ch = getcpp(fp)) != EOF) {
                          if (ch == '/' && lastc == '*') {
                              break;
                          }
                          lastc = ch;
                      }
                      if (ch == EOF) {
                          fprintf(stderr, "unterminated comment\n");
                          break;
                      }
                      ch = ' ';
                  } else if (ch == '/') {
                      /* single-line comment */
                      while ((ch = getcpp(fp)) != EOF && ch != '\n')
                          continue;
                      if (ch == EOF)
                          break;
                  } else {
                      putc('/', ft);
                  }
              }
              putc(ch, ft);
          }
          fclose(fp);
          fclose(ft);
          return 0;
      }
      

      【讨论】:

      • @Muskaan:如果这个答案对您有帮助,您可以通过点击其分数下方的灰色复选标记来接受它。
      【解决方案6】:

      你可以试试这样的:

      #include <stdio.h>
      #include <string.h>
      
      #define READ 0
      #define SINGLE_LINE_COMMENT 1
      #define MULTILINE_COMMENT 2
      #define STRING_READ 3
      #define CHAR_READ 4
      int row = 1;
      int col = 0;
      int er_line = 0;
      int er_col = 0;
      void read_source(FILE *src, FILE *dst, int flag, char prev_char, int past_read)
      {
          if (feof(src))
          {
              if (flag == STRING_READ)
              {
                  printf("Error : non-terminatig string at line :%d col :%d \n", er_line, er_col);
              }
              if (flag == CHAR_READ)
              {
                  printf("Error : non-terminatig char constant at line :%d col :%d  \n", er_line, er_col);
              }
              if (flag == MULTILINE_COMMENT)
              {
                  printf("Error : comment reach to end of file at line :%d col :%d \n", er_line, er_col);
              }
              fclose(src);
              fclose(dst);
              return;
          }
      
          char ch = fgetc(src);
          past_read++;
          if (ch == '\n')
          {
              row++;
              col = 0;
          }
          else
          {
              col++;
          }
          char next_ch = '\0';
          switch (ch)
          {
          case '\n':
              if (flag == SINGLE_LINE_COMMENT)
              {
                  flag = READ;
                  past_read = 0;
              }
              else
              {
                  if (flag == STRING_READ)
                  {
                      printf("Error : non-terminatig string at line :%d col :%d \n", er_line, er_col);
                      return;
                  }
                  if (flag == CHAR_READ)
                  {
                      printf("Error : non-terminatig char constant at line :%d col :%d  \n", er_line, er_col);
                      return;
                  }
              }
              break;
          case '/':
              next_ch = fgetc(src);
              if (next_ch == '/')
              {
                  if (flag != STRING_READ && flag != CHAR_READ && flag != SINGLE_LINE_COMMENT && flag != MULTILINE_COMMENT)
                  {
                      flag = SINGLE_LINE_COMMENT;
                      er_line = row;
                      er_col = col;
                      past_read = 0;
                  }
              }
              else
              {
                  if (next_ch == '*')
                  {
                      if (flag != STRING_READ && flag != CHAR_READ && flag != SINGLE_LINE_COMMENT && flag != MULTILINE_COMMENT)
                      {
                          flag = MULTILINE_COMMENT;
                          er_line = row;
                          er_col = col;
                          past_read = 0;
                      }
                  }
                  else
                  {
                      fseek(src, -1, SEEK_CUR);
                  }
              }
              break;
          case '"':
              if (prev_char != '\\')
              {
                  if (flag == STRING_READ)
                  {
                      flag = READ;
                      past_read = 0;
                  }
                  else
                  {
                      if (flag != STRING_READ && flag != CHAR_READ && flag != SINGLE_LINE_COMMENT && flag != MULTILINE_COMMENT)
                      {
                          flag = STRING_READ;
                          er_line = row;
                          er_col = col;
                          past_read = 0;
                      }
                  }
              }
              break;
          case '\'':
              if (prev_char != '\\')
              {
                  if (flag == CHAR_READ)
                  {
                      flag = READ;
                      past_read = 0;
                  }
                  else
                  {
                      if (flag != STRING_READ && flag != CHAR_READ && flag != SINGLE_LINE_COMMENT && flag != MULTILINE_COMMENT)
                      {
                          flag = CHAR_READ;
                          er_line = row;
                          er_col = col;
                          past_read = 0;
                      }
                  }
              }
              else
              {
                  if (flag == CHAR_READ)
                  {
                      if (past_read > 2)
                      {
                          flag = READ;
                          past_read = 0;
                      }
                  }
              }
              break;
          case '*':
              if (flag == MULTILINE_COMMENT)
              {
                  next_ch = fgetc(src);
                  if (next_ch == '/')
                  {
                      ch = '\0';
                      flag = READ;
                      past_read = 0;
                  }
                  else
                  {
                      fseek(src, -1, SEEK_CUR);
                  }
              }
              break;
          }
      
          //to work with char constant
          if (flag == CHAR_READ)
          {
              if (ch != '\\')
              {
                  if (prev_char != '\\')
                  {
                      if (past_read > 3)
                      {
                          printf(" Error : non-terminatig char constant at line :%d col :%d\n", er_line, er_col);
                          return;
                      }
                  }
              }
              else
              {
                  if (past_read > 3)
                  {
                      printf(" Error : non-terminatig char constant at line :%d col :%d\n", er_line, er_col);
                      return;
                  }
              }
          }
      
          if (flag != MULTILINE_COMMENT && flag != SINGLE_LINE_COMMENT && ch != '\0' && ch != EOF)
          {
              fputc(ch, dst);
          }
      
          read_source(src, dst, flag, ch, past_read);
          return;
      }
      
      int main(int argc, char **argv)
      {
      
          FILE *fp = fopen(argv[1], "r");
          FILE *fp2 = NULL;
          if (fp == NULL)
          {
              printf("Unable to open file %s\n", argv[1]);
              return 0;
          }
          fp2 = fopen(argv[2], "w");
          if (fp2 == NULL)
          {
              printf("Unable to open file %s\n", argv[2]);
          }
          read_source(fp, fp2, READ, '\0', 0);
          return 0;
      }
      

      【讨论】:

        【解决方案7】:
        /* This file is to remove all comments from a c/c++ source file */
        /* Modified by John Dai 2020-05-06 */
        
        #include <stdio.h>
        
        int main (void)
        {
          char *sourceFile = "D:/Temp/MyCfile.cpp"; //your source code
          char *outputFile = "D:/Temp/MyCfileWoComments.cpp"; //output file
        
          FILE *fp, *ft;
          char ch, nextc;
        
          fp = fopen (sourceFile, "r");
          ft = fopen (outputFile, "w");
          if (fp == NULL) {printf ("Error in opening source file\n"); return 1;}
          if (ft == NULL) {printf ("Error in opening output file\n"); return 1;}
        
          nextc = fgetc (fp);
          while (nextc != EOF)
            {
              ch = nextc;
              nextc = fgetc (fp);
        
        
              if ((ch == '/') && (nextc == '/'))
              {
                  nextc = fgetc (fp);
                  while (nextc != '\n') {// move to the end of line
                      nextc = fgetc (fp);
                  }
                  ch = nextc; //end of line character
                  nextc = fgetc(fp); //read 1st character from a new line
              }
        
        
              else if ((ch == '/') && (nextc == '*')){
              {
                  nextc = fgetc (fp);
                  while (!((ch == '*') && (nextc == '/'))) {/* move to the end of comment*/
                      ch = nextc;
                      nextc = fgetc (fp);
                  }
                  ch = fgetc (fp); //read first character after the end of comment block
                  nextc = fgetc (fp);
                }
              }
        
              putc (ch, ft);
        
            }
        
          fclose (fp);
          fclose (ft);
          return 0;
        }
        

        【讨论】:

        • 最好在你的回答中提供一些解释。
        • 您的代码中存在多个问题:如果文件以// 结尾而不后跟换行符,则无限循环;如果文件具有未终止的/* 注释,则无限循环。不支持可以包含///* 序列的转义换行符、字符常量或字符串常量。
        猜你喜欢
        • 2021-01-04
        • 2010-11-04
        • 2017-01-19
        • 2011-05-23
        • 2014-04-22
        • 1970-01-01
        • 1970-01-01
        • 2010-09-28
        • 1970-01-01
        相关资源
        最近更新 更多