前言

有时为了信息保密或是单纯阅读代码,我们需要删除注释。

之前考虑过正则表达式,但是感觉实现起来相当麻烦。而状态机可以把多种情况归为一类状态再行分解,大大简化问题。本文就是基于状态机实现的。

目录

  • 删除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外,其余状态下均需进行字符(串)处理,以保持正确输出。详见文末代码。

删除Java代码注释

需要考虑的情况

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

状态转移描述

可以看到,java中的注释规则更为简单,其中/** */完全可以用/* */的状态涵盖。且不会出现折行注释和字符串折行的情况,因此状态更加简单,有兴趣的可以画一画,这里就不画图了。换句话说,上面删除C/C++注释的程序完全可以用来删除java注释。

程序

 import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader; import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.BufferedWriter; import java.io.IOException; import java.util.Scanner; /**
* @author xiaoxi666
* @version 1.0.0 2017.12.01
*/ public class deleteCAndCplusplusAndJavaNote { /**
* 状态
*/
enum State {
CODE, // 正常代码
SLASH, // 斜杠
NOTE_MULTILINE, // 多行注释
NOTE_MULTILINE_STAR, // 多行注释遇到*
NOTE_SINGLELINE, // 单行注释
BACKSLASH, // 折行注释
CODE_CHAR, // 字符
CHAR_ESCAPE_SEQUENCE, // 字符中的转义字符
CODE_STRING, // 字符串
STRING_ESCAPE_SEQUENCE// 字符串中的转义字符
}; /**
* @function 删除代码中的注释,以String形式返回
* @param strToHandle 待删除注释的代码
* @return 已删除注释的代码,String字符串形式
*/
public static String delete_C_Cplusplus_Java_Note(String strToHandle) {
StringBuilder builder = new StringBuilder(); State state = State.CODE;// Initiate
for (int i = 0; i < strToHandle.length(); ++i) {
char c = strToHandle.charAt(i);
switch (state) {
case CODE:
if (c == '/') {
state = State.SLASH;
}else {
builder.append(c);
if(c=='\'') {
state=State.CODE_CHAR;
}else if(c=='\"') {
state=State.CODE_STRING;
}
}
break;
case SLASH:
if (c == '*') {
state = State.NOTE_MULTILINE;
} else if (c == '/') {
state = State.NOTE_SINGLELINE;
} else {
builder.append('/');
builder.append(c);
state = State.CODE;
}
break;
case NOTE_MULTILINE:
if(c=='*') {
state=State.NOTE_MULTILINE_STAR;
}else {
if(c=='\n') {
builder.append("\r\n");//保留空行,当然,也可以去掉
}
state=State.NOTE_MULTILINE;//保持当前状态
}
break;
case NOTE_MULTILINE_STAR:
if(c=='/') {
state=State.CODE;
}else if(c=='*') {
state=State.NOTE_MULTILINE_STAR;//保持当前状态
}
else {
state=State.NOTE_MULTILINE;
}
break;
case NOTE_SINGLELINE:
if(c=='\\') {
state=State.BACKSLASH;
}else if(c=='\n'){
builder.append("\r\n");
state=State.CODE;
}else {
state=State.NOTE_SINGLELINE;//保持当前状态
}
break;
case BACKSLASH:
if(c=='\\' || c=='\r'||c=='\n') {//windows系统换行符为\r\n
if(c=='\n') {
builder.append("\r\n");//保留空行,当然,也可以去掉
}
state=State.BACKSLASH;//保持当前状态
}else {
state=State.NOTE_SINGLELINE;
}
break;
case CODE_CHAR:
builder.append(c);
if(c=='\\') {
state=State.CHAR_ESCAPE_SEQUENCE;
}else if(c=='\'') {
state=State.CODE;
}else {
state=State.CODE_CHAR;//保持当前状态
}
break;
case CHAR_ESCAPE_SEQUENCE:
builder.append(c);
state=State.CODE_CHAR;
break;
case CODE_STRING:
builder.append(c);
if(c=='\\') {
state=State.STRING_ESCAPE_SEQUENCE;
}else if(c=='\"') {
state=State.CODE;
}else {
state=State.CODE_STRING;//保持当前状态
}
break;
case STRING_ESCAPE_SEQUENCE:
builder.append(c);
state=State.CODE_STRING;
break;
default:
break;
}
}
return builder.toString();
} /**
* @function 从指定文件中读取代码内容,以String形式返回
* @param inputFileName 待删除注释的文件
* @return 待删除注释的文件中的代码内容,String字符串形式
* @note 输入文件格式默认为 UTF-8
*/
public static String readFile(String inputFileName) {
StringBuilder builder = new StringBuilder();
try {
FileInputStream fis = new FileInputStream(inputFileName);
InputStreamReader dis = new InputStreamReader(fis);
BufferedReader reader = new BufferedReader(dis);
String s;
// 每次读取一行,当改行为空时结束
while ((s = reader.readLine()) != null) {
builder.append(s);
builder.append("\r\n");// windows系统换行符
}
reader.close();
dis.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
return builder.toString();
} /**
* @function 将删除注释后的代码保存到指定新文件
* @param outputFileName 保存“删除注释后的代码”的文件的文件名
* @param strHandled 删除注释后的代码
*/
public static void writeFile(String outputFileName, String strHandled) {
try {
FileOutputStream fos = new FileOutputStream(outputFileName);
OutputStreamWriter dos = new OutputStreamWriter(fos);
BufferedWriter writer = new BufferedWriter(dos);
writer.write(strHandled);
writer.close();
dos.close();
fos.close();
System.out.println("code that without note has been saved successfully in " + outputFileName);
} catch (IOException e) {
e.printStackTrace();
}
} /**
* @function 读取待处理文件,删除注释,处理过的代码写入新文件
* @param args
*/
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
//待删除注释的文件
System.out.println("The fileName that will be delete note:");
String inputFileName = in.nextLine();
//保存“删除注释后的代码”的文件
System.out.println("The fileName that will save code without note:");
String outputFileName = in.nextLine(); String strToHandle = readFile(inputFileName);
String strHandled = delete_C_Cplusplus_Java_Note(strToHandle);
writeFile(outputFileName, strHandled); } }

说明

  • 本程序保留注释占用行,也就是说,注释以外的代码原样保留(行数也不会变),注释行变为空白。
  • 不检测文件后缀(这就意味着把代码写在.txt里面也可以处理),有需求的可以自行添加。
  • 本程序适用于windows平台,其他平台如linux和mac请替换“\r\n”换行符。文件格式默认为UTF。
  • 有兴趣的可以封装成图形界面,直接拖入文件处理,更好用。
  • 本程序经过大量测试未发现bug,若读者发现bug,欢迎提出。

参考

状态机编程思想(2):删除代码注释(目前支持C/C++和Java)的更多相关文章

  1. 《Java编程思想第四版》附录 B 对比 C++和 Java

    <Java编程思想第四版完整中文高清版.pdf>-笔记 附录 B 对比 C++和 Java “作为一名 C++程序员,我们早已掌握了面向对象程序设计的基本概念,而且 Java 的语法无疑是 ...

  2. ★ java删除代码注释

    package com.witwicky.util; import java.io.BufferedReader; import java.io.BufferedWriter; import java ...

  3. [Java编程思想-学习笔记]第3章 操作符

    3.1  更简单的打印语句 学习编程语言的通许遇到的第一个程序无非打印"Hello, world"了,然而在Java中要写成 System.out.println("He ...

  4. 面向对象的编程思想和Java中类的概念与设计

    面向对象的编程思想学习,面向对象内容的三条主线;1.java类及类的对象2.面向对象的三大特征3.其他关键字学习内容:3.1面向对象与面向过程面向对象与面向过程在应用上的区别 Java中类的概念与设计 ...

  5. 关于 java编程思想第五版 《On Java 8》

    On Java 8中文版 英雄召集令 这是该项目的GITHUB地址:https://github.com/LingCoder/OnJava8 广招天下英雄,为开源奉献!让我们一起来完成这本书的翻译吧! ...

  6. 怎样删除C/C++代码中的所有注释?浅谈状态机的编程思想

    K&R习题1-23中,要求“编写一个程序,删除C语言程序中所有的注释语句.要正确处理带引号的字符串与字符常量.在C语言中,注释不允许嵌套”. 如果不考虑字符常量和字符串常量,问题确实很简单.只 ...

  7. 撰写一篇博客要求讲述四则运算2的设计思想,源程序代码、运行结果截图、编程总结分析,并按照PSP0级的要求记录开发过程中的时间记录日志。

    一.撰写一篇博客要求讲述四则运算2的设计思想,源程序代码.运行结果截图.编程总结分析,并按照PSP0级的要求记录开发过程中的时间记录日志. 1.设计思想: ①创建test.jsp建立第一个前端界面,提 ...

  8. 函数式编程思想概述和冗余的Runnable代码

    函数式编程思想概述 在数学中,函数就是有输入量.输出量的一套计算方法 相对而言,面向对象过分强调必须通过对象的形式来做事情,而函数式的思想是尽量忽略复杂的面向对象的复杂语法--是强调做什么而不是以什么 ...

  9. Eclipse删除代码中所有注释及空格

    替换方法: Ctrl+F 删除java注释:  /\*{1,2}[\s\S]*?\*/ Ctrl+F 删除xml注释:  <!-[\s\S]*?--> Ctrl+F 删除空白行:   ^\ ...

随机推荐

  1. BZOJ-3040-最短路(road)

    Description N个点,M条边的有向图,求点1到点N的最短路(保证存在).1<=N<=1000000,1<=M<=10000000 Input 第一行两个整数N.M,表 ...

  2. 树莓派.系统.修改声音输出通道(auto,hdmi,耳机接口)

    树莓派平时通过耳机接口一直在正常使用 有一天外接了一个HDMI的屏幕, 结果耳机接口连着的音箱突然就没声音了,在网上查了资料,发现原来树莓派声音输出有3种模式 记录如下: 在命令行终端上输入下面命令将 ...

  3. 初识Http协议抓包工具—Fiddler

    1.Fiddler简介 Fiddler是用一款使用C#编写的http协议调试代理工具.它支持众多的http调试任务,能够记录并检查所有你的电脑和互联网之间的http通讯,可以设置断点,查看所有的“进出 ...

  4. JavaScrpit中异步请求Ajax实现

    在前端页面开发的过程中,经常使用到Ajax请求,异步提交表单数据,或者异步刷新页面. 一般来说,使用Jquery中的$.ajax,$.post,$.getJSON,非常方便,但是有的时候,我们只因为需 ...

  5. Assignments

    Assignments Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  6. 多线程环境下非安全Dictionary引起的“已添加了具有相同键的项”问题

    问题: 代码是在多线程环境下,做了简单的Key是否存的判断, 测试代码如下: public class Program { static Dictionary<string, Logger> ...

  7. 服务器 : Apache Tomcat - 理解架构层次

    文章概览 相信很多接触java的人都对Tom猫有着多少的熟悉,就个人而言,本来只知道Tom简单的操作与配置,就像裹上一层纱,迷迷糊糊的. Tomcat的书籍本来就不多,高分的还是很久之前的版本,直到最 ...

  8. 二叉搜索树 (BST) 的创建以及遍历

    二叉搜索树(Binary Search Tree) : 属于二叉树,其中每个节点都含有一个可以比较的键(如需要可以在键上关联值), 且每个节点的键都大于其左子树中的任意节点而小于右子树的任意节点的键. ...

  9. 用C#生成不重复的随机数

    我们在做能自动生成试卷的考试系统时,常常需要随机生成一组不重复的题目,在.net Framework中提供了一个专门用来产生随机数的类System.Random. 对于随机数,大家都知道,计算机不 可 ...

  10. 《天书夜读:从汇编语言到windows内核编程》三 练习反汇编C语言程序

    1) Debug版本算法反汇编,现有如下3×3矩阵相乘的程序: #define SIZE 3 int MyFunction(int a[SIZE][SIZE],int b[SIZE][SIZE],in ...