狀態機編程思想(2):刪除代碼註釋(目前支持C/C++和Java)

前言

有時爲了信息保密或是單純閱讀代碼,咱們須要刪除註釋。html

以前考慮過正則表達式,可是感受實現起來至關麻煩。而狀態機能夠把多種狀況歸爲一類狀態再行分解,大大簡化問題。本文就是基於狀態機實現的。java

目錄

  • 刪除C/C++代碼註釋
  • 刪除Java代碼註釋
  • 程序
  • 參考

刪除C/C++代碼註釋

須要考慮的狀況

  • //
  • /* */
  • //和/* */嵌套(注意不存在/* */和/* */嵌套)
  • 折行註釋(用\間隔)
  • 字符中存在的/和*
  • 字符串中存在的//和/* */
  • 字符串中的折行代碼(用\間隔)
  • 頭文件中可能存在的/

狀態轉移描述

思路參考了博客http://www.cnblogs.com/zhanghaiba/p/3569928.html#3853787,寫得很贊。正則表達式

本文基於上面所述博文進行了如下修改或是優化:編程

  • 原博文沒有考慮/***/的狀況(其中*的個數爲奇數),已修正
  • 切換到了windows平臺下,支持windows換行\r\n(並請注意:若是原文件末尾沒有回車,會自動插入)
  • 狀態量優化爲枚舉常量
  • 狀態轉移由if...else...elseif結構改成switch...case結構,更爲清晰,對於大型代碼,效率更高

 

 

 其中,除狀態NOTE_MULTILINE_STAR外,其他狀態下均需進行字符(串)處理,以保持正確輸出。詳見文末代碼。windows

 

刪除Java代碼註釋

須要考慮的狀況

  • //
  • /* */
  • /** */
  • //和/**/嵌套(注意不存在/* */和/* */嵌套,不存在/** */和/** */嵌套,不存在/* */和/** */嵌套)
  • //和/** */嵌套
  • 字符中存在的/和*
  • 字符串中存在的//、/**/以及/** */

狀態轉移描述

 能夠看到,java中的註釋規則更爲簡單,其中/** */徹底能夠用/* */的狀態涵蓋。且不會出現折行註釋和字符串折行的狀況,所以狀態更加簡單,有興趣的能夠畫一畫,這裏就不畫圖了。換句話說,上面刪除C/C++註釋的程序徹底能夠用來刪除java註釋。app

 

程序

複製代碼
  1 import java.io.FileInputStream;
  2 import java.io.InputStreamReader;
  3 import java.io.BufferedReader;
  4 
  5 import java.io.FileOutputStream;
  6 import java.io.OutputStreamWriter;
  7 import java.io.BufferedWriter;
  8 
  9 import java.io.IOException;
 10 
 11 import java.util.Scanner;
 12 
 13 /**
 14  * @author xiaoxi666
 15  * @version 1.0.0 2017.12.01
 16  */
 17 
 18 public class deleteCAndCplusplusAndJavaNote {
 19 
 20     /**
 21      * 狀態
 22      */
 23     enum State {
 24         CODE, // 正常代碼
 25         SLASH, // 斜槓
 26         NOTE_MULTILINE, // 多行註釋
 27         NOTE_MULTILINE_STAR, // 多行註釋遇到*
 28         NOTE_SINGLELINE, // 單行註釋
 29         BACKSLASH, // 折行註釋
 30         CODE_CHAR, // 字符
 31         CHAR_ESCAPE_SEQUENCE, // 字符中的轉義字符
 32         CODE_STRING, // 字符串
 33         STRING_ESCAPE_SEQUENCE// 字符串中的轉義字符
 34     };
 35 
 36     /**
 37      * @function 刪除代碼中的註釋,以String形式返回
 38      * @param strToHandle 待刪除註釋的代碼
 39      * @return 已刪除註釋的代碼,String字符串形式
 40      */
 41     public static String delete_C_Cplusplus_Java_Note(String strToHandle) {
 42         StringBuilder builder = new StringBuilder();
 43 
 44         State state = State.CODE;// Initiate
 45         for (int i = 0; i < strToHandle.length(); ++i) {
 46             char c = strToHandle.charAt(i);
 47             switch (state) {
 48             case CODE:
 49                 if (c == '/') {
 50                     state = State.SLASH;
 51                 }else {
 52                     builder.append(c);
 53                     if(c=='\'') {
 54                         state=State.CODE_CHAR;
 55                     }else if(c=='\"') {
 56                         state=State.CODE_STRING;
 57                     }
 58                 }                    
 59                 break;
 60             case SLASH:
 61                 if (c == '*') {
 62                     state = State.NOTE_MULTILINE;
 63                 } else if (c == '/') {
 64                     state = State.NOTE_SINGLELINE;
 65                 } else {
 66                     builder.append('/');
 67                     builder.append(c);
 68                     state = State.CODE;
 69                 }
 70                 break;
 71             case NOTE_MULTILINE:
 72                 if(c=='*') {
 73                     state=State.NOTE_MULTILINE_STAR;
 74                 }else {
 75                     if(c=='\n') {
 76                         builder.append("\r\n");//保留空行,固然,也能夠去掉
 77                     }
 78                     state=State.NOTE_MULTILINE;//保持當前狀態
 79                 }
 80                 break;
 81             case NOTE_MULTILINE_STAR:
 82                 if(c=='/') {
 83                     state=State.CODE;
 84                 }else if(c=='*') {
 85                     state=State.NOTE_MULTILINE_STAR;//保持當前狀態
 86                 }
 87                 else {
 88                     state=State.NOTE_MULTILINE;
 89                 }
 90                 break;
 91             case NOTE_SINGLELINE:
 92                 if(c=='\\') {
 93                     state=State.BACKSLASH;
 94                 }else if(c=='\n'){
 95                     builder.append("\r\n");
 96                     state=State.CODE;
 97                 }else {
 98                     state=State.NOTE_SINGLELINE;//保持當前狀態
 99                 }
100                 break;
101             case BACKSLASH:
102                 if(c=='\\' || c=='\r'||c=='\n') {//windows系統換行符爲\r\n
103                     if(c=='\n') {
104                         builder.append("\r\n");//保留空行,固然,也能夠去掉
105                     }
106                     state=State.BACKSLASH;//保持當前狀態
107                 }else {
108                     state=State.NOTE_SINGLELINE;
109                 }
110                 break;
111             case CODE_CHAR:
112                 builder.append(c);
113                 if(c=='\\') {
114                     state=State.CHAR_ESCAPE_SEQUENCE;
115                 }else if(c=='\'') {                    
116                     state=State.CODE;
117                 }else {
118                     state=State.CODE_CHAR;//保持當前狀態
119                 }
120                 break;
121             case CHAR_ESCAPE_SEQUENCE:
122                 builder.append(c);
123                 state=State.CODE_CHAR;
124                 break;
125             case CODE_STRING:
126                 builder.append(c);
127                 if(c=='\\') {
128                     state=State.STRING_ESCAPE_SEQUENCE;
129                 }else if(c=='\"') {                    
130                     state=State.CODE;
131                 }else {
132                     state=State.CODE_STRING;//保持當前狀態
133                 }
134                 break;
135             case STRING_ESCAPE_SEQUENCE:
136                 builder.append(c);
137                 state=State.CODE_STRING;
138                 break;
139             default:
140                 break;
141             }
142         }
143         return builder.toString();
144     }
145 
146     /**
147      * @function 從指定文件中讀取代碼內容,以String形式返回
148      * @param inputFileName 待刪除註釋的文件
149      * @return 待刪除註釋的文件中的代碼內容,String字符串形式
150      * @note 輸入文件格式默認爲 UTF-8
151      */
152     public static String readFile(String inputFileName) {
153         StringBuilder builder = new StringBuilder();
154         try {
155             FileInputStream fis = new FileInputStream(inputFileName);
156             InputStreamReader dis = new InputStreamReader(fis);
157             BufferedReader reader = new BufferedReader(dis);
158             String s;
159             // 每次讀取一行,當改行爲空時結束
160             while ((s = reader.readLine()) != null) {
161                 builder.append(s);
162                 builder.append("\r\n");// windows系統換行符
163             }
164             dis.close();
165         } catch (IOException e) {
166             e.printStackTrace();
167             System.exit(1);
168         }
169         return builder.toString();
170     }
171 
172     /**
173      * @function 將刪除註釋後的代碼保存到指定新文件
174      * @param outputFileName 保存「刪除註釋後的代碼」的文件的文件名
175      * @param strHandled 刪除註釋後的代碼
176      */
177     public static void writeFile(String outputFileName, String strHandled) {
178         try {
179             FileOutputStream fos = new FileOutputStream(outputFileName);
180             OutputStreamWriter dos = new OutputStreamWriter(fos);
181             BufferedWriter writer = new BufferedWriter(dos);
182             writer.write(strHandled);
183             writer.close();
184             System.out.println("Code that without note has been saved successfully in " + outputFileName);
185         } catch (IOException e) {
186             e.printStackTrace();
187         }
188     }
189 
190     /**
191      * @function 讀取待處理文件,刪除註釋,處理過的代碼寫入新文件
192      * @param args
193      */
194     public static void main(String[] args) {
195         Scanner in = new Scanner(System.in);
196         //待刪除註釋的文件
197         System.out.println("The fileName that will be delete note:");
198         String inputFileName = in.nextLine();
199         //保存「刪除註釋後的代碼」的文件
200         System.out.println("The fileName that will save code without note:");
201         String outputFileName = in.nextLine();
202         
203         String strToHandle = readFile(inputFileName);
204         String strHandled = delete_C_Cplusplus_Java_Note(strToHandle);
205         writeFile(outputFileName, strHandled);
206         
207     }
208 
209 }
複製代碼

 

說明

  • 本程序保留註釋佔用行,也就是說,註釋之外的代碼原樣保留(行數也不會變),註釋行變爲空白。
  • 不檢測文件後綴(這就意味着把代碼寫在.txt裏面也能夠處理),有需求的能夠自行添加。
  • 文件格式默認爲UTF。
  • 有興趣的能夠封裝成圖形界面,直接拖入文件處理,更好用。
  • 本程序通過大量測試未發現bug,若讀者發現bug,歡迎提出。

 

參考

 

出處:http://www.cnblogs.com/xiaoxi666/p/7931763.htmlpost

相關文章
相關標籤/搜索