一个比较常见的题。这个题应该是要比看上去的难不少。如果用正则,可能会好一些。
使用FSM解答。
核心思想是向后看一步。
对于每次读入的字符,实际上我们不能立即判断出它是否是注释,只有向后多看一个,来判断前面读到的这个字符是代码还是注释。
例如:  te/st//comment
假设有个缓存,长度是2个字节,存储当前处理的字符和上一个字符。
第一次读到‘/’时,缓存中是“e/”,输出“e”.
读下一个,缓存中是“/s”,不匹配注释,“/”直接被输出
下一次读到‘/’时,缓存中是“t/”, 这时我们可以知道t不是注释中的一部分,直接输出。
下一步,缓存就为“//”,我们知道了这个和一个注释开始符匹配,剩下的就当做注释处理。

同样的,在判断注释结束时,我们依然要多向后看一部。

下面给出一个示意的有限状态自动机。用queue代表缓存,然后使用一个flag comments来标记是否是注释。
这里仅仅是一个示意图,表示了关键的一部分。实际还有很多缺失的细节。
1.注释有//和/* */两种,因此开始注释和结束注释的判断都不一样。
2.要考虑转义字符的问题。
3.处理结束后,要将缓存中剩余的2个char根据状态输出。
具体细节可以参考下面的代码。(未经完全测试)

使用有限状态自动机过滤掉java和c++中的注释-LMLPHP

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. char* filter(const char* input){
  4.     if(input == NULL) return NULL;

  5.     int len = strlen(input) +1;

  6.     char* ret = (char*)malloc(len);
  7.     int index = 0;
  8.     int r = 0;
  9.     int comments = 0;
  10.     char cache[3];
  11.     cache[0] = '\0';
  12.     cache[1] = '\0';
  13.     cache[2] = '\0';
  14.     for(;r<len;r++){
  15.         cache[strlen(cache)] = input[r];
  16.         if(strlen(cache)!=2)
  17.             continue;
  18.         if(comments>0){
  19.             if(comments == 1 && cache[1] == '\n'){
  20.                 cache[0] = '\0';
  21.                 cache[1] = '\0';
  22.                 comments = 0;
  23.                 continue;
  24.             }
  25.             if(comments == 1 && cache[1] != '\n'){
  26.                 cache[0] = cache[1];
  27.                 cache[1] = '\0';
  28.                 continue;
  29.             }
  30.             if(comments == 2 && cache[0] == '*'&& cache[1] == '/'){
  31.                 cache[0] = '\0';
  32.                 cache[1] = '\0';
  33.                 comments = 0;
  34.                 continue;
  35.             }
  36.             if(comments == 2 && !(cache[0] == '*'&& cache[1] == '/')){
  37.                 cache[0] = cache[1];
  38.                 cache[1] = '\0';
  39.                 continue;
  40.             }
  41.                 
  42.         }
  43.         else{
  44.                         //escape char
  45.             if(cache[0] =='\\'){
  46.                 ret[index++] = cache[0];
  47.                 ret[index++] = cache[1];
  48.                 cache[0] = '\0';
  49.                 cache[1] = '\0';
  50.                 continue;
  51.             }
  52.             if(cache[0] =='/' && cache[1] == '/'){
  53.                 comments = 1;
  54.                 cache[0] = '\0';
  55.                 cache[1] = '\0';
  56.                 continue;
  57.             }
  58.             if(cache[0] =='/' && cache[1] == '*'){
  59.                 comments = 2;
  60.                 cache[0] = '\0';
  61.                 cache[1] = '\0';
  62.                 continue;
  63.             }
  64.             ret[index++] = cache[0];
  65.             cache[0]=cache[1];
  66.             cache[1]='\0';
  67.             
  68.         }
  69.     }
  70.     if(comments == 0){
  71.         ret[index++] = cache[0];
  72.         ret[index++] = cache[1];

  73.     }
  74.     ret[index] = '\0';
  75.     return ret;    
  76. }

  77. int main(){
  78.     char* test = "I just for test /*test*/ test";
  79.     char* test1 = "I just for test //comments \ntest";
  80.     char* test2 = "I just for test \\///comments";
  81.     printf("%s \n", filter(test));
  82.     printf("%s \n", filter(test1));
  83.     printf("%s \n", filter(test2));
  84. }




09-19 00:45