当前位置 博文首页 > Janbar:c语言版去除源代码注释

    Janbar:c语言版去除源代码注释

    作者:[db:作者] 时间:2021-07-05 16:24

    1. 去除代码中注释需要注意下面几点
      首先注释有”/*”开始到”*/”结束的多行或单行注释
      其次还有”//”这种单行注释
      另外还需要注意双引号和单引号内的字符不要算到注释中
    2. 因此我设计以下程序
      当遇到”“双引号和”“时需要跳过整个字符串,特别注意字符串和字符内部转义字符。
      当遇到”/“斜杠时,匹配下一个为星号还是斜杠,如果下一个是斜杠则直接跳到本行结尾。如果是星号则匹配”*/
    3. 下面是源代码,没啥特别的
    #include <stdio.h>
    #include <ctype.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    
    /**
    * 去掉字符串中注释部分
    **/
    void remove_comment(char *buf)
    {
      size_t off;
      char *s, *p, *t, *tmp;
      char *sss="adas\"d/**/\"*a\"//s/**/d*/"; // 这里主要测试字符串内带注释字符
    
      for (s = p = buf; *p != '\0'; p++) {
        switch(*p) {
          case '"': // 直接循环到下一个 "
          case '\'': /* 直接循环到下一个 ' */
              // 下面找到字符串结束位置,避免匹配字符串内部的 /* 或者 //
            for (tmp = p + 1; *tmp != *p; tmp++) {
              if (*tmp == '\\') {
                tmp++; /* 跳过转义位置,因为转义字符2个位置代表一个字符 */
              }
            }//阿萨德撒
    
            // while(1) {
              // if ( NULL != (t = strchr(tmp, '\\')) ) {
            // printf("%c\n", *tmp);
                // tmp = t + 2; // 有转义字符
              // }
              // if ( NULL != (t = strchr(tmp, *p)) ) {
                // tmp = t + 1; // 有要找的字符
                // break;
              // }
            // }
            // printf("%c\n", *(tmp-2));
            // exit(0);
            // while ( NULL != (t = strchr(tmp, *p)) ) {
              // tmp = t + 1; /*每次都从下一个位置找*/
              // if ( *(t - 1) != '\\' ) {
                // break; // 这次的符号不是转义,则表示找到真正字符串末尾了
              // }
            // }
    
            off = tmp - p+1/* 计算本次拷贝长度 */;
            if (off > 1) {
              strncpy(s, p, off);
              p += off - 1; // 外面有一个p++,所以这里少加一个
              s += off;
            }
          break;
    
          case '/':
            switch ( *(p + 1) ) {
              case '*': // 组成 /*
                if (NULL != (t = strstr(p + 1, "*/"))) {
                  p = t + 1; /* 这里把指针指向 /* 结束标记 */
                }
              break;
    
              case '/':  //  组成 //
                for (tmp = p - 1; 0 != isspace(*tmp); tmp--) {
                } // /* 这里的循环用于去掉空行注释
                s -= p - tmp - 1; // s倒退到上一个非空白字符
                *s++ = '\n'; /* //是单行注释,因此必须有一个换行 */
    
                while (*p != '\n' && *p != '\r') {
                  p++;//  p指针移到下一个回车换行
                }
              break;
    
              default: // 没有匹配注释字符
                *s++ = *p;
              break;
            }
          break;
    
          default: // 没有匹配字符则逐个写
            *s++ = *p;
          break;
        }
      }
    
      *s = '\0'; // 写结束标记
    }
    
    /**
    * 因为一个源码文件最大也就几M
    * 所以全部读到内存处理,绰绰有余的
    * 这里是多行注释,去掉后会有一个回车
    * 及多行注释缩短为一行
    **/
    int main(int argc, char *argv[])
    {
      if (argc != 2) { /* 传递参数不正确 */
        printf("Usage : %s file.c\n", argv[0]);
        return -1;
      }
      const char *filename = argv[1]; // 得到文件名
    
      struct stat statbuff;  /* 得到文件信息结构体 */
      if(stat(filename, &statbuff) < 0){
        return -1; // 获取文件大小失败
      }
    
      off_t filesize = statbuff.st_size; // 缓存文件大小
      char *fileBuff = (char *)malloc(sizeof(char) * filesize);
    
      int fd = open(filename, O_RDONLY);
      if (-1 == fd) {
        printf("open %s : %s\n", filename, strerror(errno));
        return errno;
      }
    
      ssize_t n = read(fd, fileBuff, filesize);
      if (n <= 0) { // 读取错误或空文件,直接关闭文件并退出
        close(fd);
        return -1;
      }
    
      *(fileBuff + n) = '\0'; /* 加上结束符 */
      remove_comment(/* 直接把参数分成2半咯 */fileBuff); // 去除注释
      printf("%s\n", fileBuff); /* 打印结果 */
    
      close(fd);
      return 0;
    }

    4.下面演示一下功能,将上面的文件保存为main.c,执行
    gcc main.c && .\a.exe main.c

    #include <stdio.h>
    #include <ctype.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    
    
    void remove_comment(char *buf)
    {
      size_t off;
      char *s, *p, *t, *tmp;
      char *sss="adas\"d/**/\"*a\"//s/**/d*/";
    
      for (s = p = buf; *p != '\0'; p++) {
        switch(*p) {
          case '"':
          case '\'':
            for (tmp = p + 1; *tmp != *p; tmp++) {
              if (*tmp == '\\') {
                tmp++;
              }
            }
    
            off = tmp - p+1;
            if (off > 1) {
              strncpy(s, p, off);
              p += off - 1;
              s += off;
            }
          break;
    
          case '/':
            switch ( *(p + 1) ) {
              case '*':
                if (NULL != (t = strstr(p + 1, "*/"))) {
                  p = t + 1;
                }
              break;
    
              case '/':
                for (tmp = p - 1; 0 != isspace(*tmp); tmp--) {
                }
                s -= p - tmp - 1;
                *s++ = '\n';
    
                while (*p != '\n' && *p != '\r') {
                  p++;
                }
              break;
    
              default:
                *s++ = *p;
              break;
            }
          break;
    
          default:
            *s++ = *p;
          break;
        }
      }
    
      *s = '\0';
    }
    
    
    int main(int argc, char *argv[])
    {
      if (argc != 2) {
        printf("Usage : %s file.c\n", argv[0]);
        return -1;
      }
      const char *filename = argv[1];
    
      struct stat statbuff;
      if(stat(filename, &statbuff) < 0){
        return -1;
      }
    
      off_t filesize = statbuff.st_size;
      char *fileBuff = (char *)malloc(sizeof(char) * filesize);
    
      int fd = open(filename, O_RDONLY);
      if (-1 == fd) {
        printf("open %s : %s\n", filename, strerror(errno));
        return errno;
      }
    
      ssize_t n = read(fd, fileBuff, filesize);
      if (n <= 0) {
        close(fd);
        return -1;
      }
    
      *(fileBuff + n) = '\0';
      remove_comment(fileBuff);
      printf("%s\n", fileBuff);
    
      close(fd);
      return 0;
    }
    cs