欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

删除Java代码中的注释

程序员文章站 2024-01-12 18:57:40
...

本文的目的在于探讨算法,纯属娱乐和活跃脑细胞。所以,不对删除注释的目的进行讨论:)这是曾经遇到的一道面试题,可惜当时对于题目的理解不到位,导致最后的解法有误。最近有空,静下心来仔细思考了一下,将解法通过BLOG记录下来。

首先,分析一下Java中注释的类型:

/*type1*/

/*
*type2
*/

//type3

 

实际上,type1和type2是同种类型,只是表现上来看,type2中包含了换行符。

最直接的解法,就是记录注释的开始位置,然后等到注释结束时进行删除操作。伪代码如下:

for(输入文本)
  if(/*)记录type1类型注释开始位置;
 else if(//)记录type2注释开始位置;
 else if(*/)根据type1的开始位置,删除注释;
 else if(\n)根据type3的开始位置,删除注释;

看起来问题就这么简单地解决了。然而,我们却没有考虑以下特殊情况:

System.out.println("/*In Mark*/");

代码中的字符串中包含了注释是不能删除的,这下问题有些棘手了。需要判断当前进行删除的注视是否位于字符串之中,所以伪代码修改如下:

for(输入文本)
 if(/*)
      if(引号开始)continue;
      else 记录type1类型注释开始位置;
 else if(//)
      if(引号开始)continue;
      else 记录type3注释开始位置;
 else if(*/)
      根据type1的开始位置,删除注释;
 else if(\n)
      根据type3的开始位置,删除注释;
 else if(")
      if(引号开始)结束引号;
      else 记录引号开始;

 

 完全解决问题了吗?如果引号之中还有一个嵌套的引号,是否会影响对引号开始的判断呢?

 当然,Java中,嵌套引号是需要引入转义符的。所以,在判断引号时,再判断一下是否为转义的引号,如果是,则不进行引号的相关处理。

分析到此为止,下面是实现的代码:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

/**
 * @author Insunny
 * 
 */
public class DelCommentsInJava {

	private static final char MARK = '"';

	private static final char SLASH = '/';

	private static final char BACKSLASH = '\\';

	private static final char STAR = '*';

	private static final char NEWLINE = '\n';
	
	//引号
	private static final int TYPE_MARK = 1;
	
	//斜杠
	private static final int TYPE_SLASH = 2;
	
	//反斜杠
	private static final int TYPE_BACKSLASH = 3;
	
	//星号
	private static final int TYPE_STAR = 4;

	// 双斜杠类型的注释
	private static final int TYPE_DSLASH = 5;

	/**
	 * 删除char[]数组中_start位置到_end位置的元素
	 * 
	 * @param _target
	 * @param _start
	 * @param _end
	 * @return
	 */
	public static char[] del(char[] _target, int _start, int _end) {
		char[] tmp = new char[_target.length - (_end - _start + 1)];
		System.arraycopy(_target, 0, tmp, 0, _start);
		System.arraycopy(_target, _end + 1, tmp, _start, _target.length - _end
				- 1);
		return tmp;
	}

	/**
	 * 删除代码中的注释
	 * 
	 * @param _target
	 * @return
	 */
	public static String delComments(String _target) {
		int preType = 0;
		int mark = -1, cur = -1, token = -1;
		// 输入字符串
		char[] input =  _target.toCharArray();
		for (cur = 0; cur < input.length; cur++) {
			if (input[cur] == MARK) {
				// 首先判断是否为转义引号
				if (preType == TYPE_BACKSLASH)
					continue;
				// 已经进入引号之内
				if (mark > 0) {
					// 引号结束
					mark = -1;
				} else {
					mark = cur;
				}
				preType = TYPE_MARK;
			} else if (input[cur] == SLASH) {
				// 当前位置处于引号之中
				if (mark > 0)
					continue;
				// 如果前一位是*,则进行删除操作
				if (preType == TYPE_STAR) {
					input = del(input, token, cur);
					// 退回一个位置进行处理
					cur = token - 1;
					preType = 0;
				} else if (preType == TYPE_SLASH) {
					token = cur - 1;
					preType = TYPE_DSLASH;
				} else {
					preType = TYPE_SLASH;
				}
			} else if (input[cur] == BACKSLASH) {
				preType = TYPE_BACKSLASH;
			} else if (input[cur] == STAR) {
				// 当前位置处于引号之中
				if (mark > 0)
					continue;
				// 如果前一个位置是/,则记录注释开始的位置
				if (preType == TYPE_SLASH) {
					token = cur - 1;
				}
				preType = TYPE_STAR;
			} else if(input[cur] == NEWLINE)
			{
				if(preType == TYPE_DSLASH)
				{
					input = del(input, token, cur);
					// 退回一个位置进行处理
					cur = token - 1;
					preType = 0;
				}
			}

		}
		return new String(input);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			File file = new File("./src/Test.java");
			BufferedReader reader = new BufferedReader(new FileReader(file));
			StringBuilder content = new StringBuilder();
			String tmp = null;
			while ((tmp = reader.readLine()) != null) {
				content.append(tmp);
				content.append("\n");
			}
			String target = content.toString();
			System.out.println(delComments(target));
		} catch (Exception e) {

		}
	}

}

 还有别的解决方案吗?能否用正则表达式来实现?继续思考中...