问题场景
项目完结后写软件操作手册时,需要统计一下整个项目有多少有效的代码行数,项目使用Java语言,涉及到前后台的脚本格式有.java、.xml、.jsp三种。
问题分析
一个脚本文件无非由注释语句,空行,和正常代码组成。发现注释语句由特定标签识别,例如Java里用’//’表示单行注释,‘/**/’表示多行注释,xml与jsp文件里用‘ ’表示注释,可以逐行读取脚本判断是否有这些特定标志与空行,剩下的就是有效代码数目。
CODE
import java.io.*;
import java.util.regex.Pattern;
/**
* Created on 2017/11/2
* Author: youxingyang.
*/
public class CountCodeNum {
/**代码行**/
private static long normalLines = 0;
/**注释行**/
private static long commentLines = 0;
/**空行**/
private static long whiteLines = 0;
private static final String JAVA = "java";
private static final String XML = "xml";
private static final String JSP = "jsp";
private static int length = 3;
private static Pattern p = Pattern.compile("^[//s&&[^//n]]*$");
private static String comm = "//";
private static String javaS = "/*";
private static String javaE = "*/";
private static String xmlS = "<!--";
private static String xmlE = "-->";
private static String jspS = "<%--";
private static String jspE = "--%>";
public static void main(String[] args) throws IOException {
countFile("D:\\IDEAWORKPLACE");
System.out.println("空行:" + whiteLines);
System.out.println("注释行:" + commentLines);
System.out.println("代码行:" + normalLines);
}
/**
* 找出该路径下的文件代码行数 -支持文件夹
* @param path 要查找的路径
*/
private static void countFile(String path) throws IOException {
File file = new File(path);
if (file.isFile()) {
count(file);
} else {
File[] childs = file.listFiles();
if (childs != null) {
for (File child : childs) {
if (!child.isDirectory()) {
count(child);
} else {
countFile(child.getAbsolutePath());
}
}
}
}
}
/**
* 选择脚本解析
* @param file 要解析的文件
* @throws IOException
*/
private static void count(File file) throws IOException {
if (!file.exists()) {
return;
}
String name = file.getName();
String suffix = name.substring(name.lastIndexOf('.') + 1);
switch (suffix.toLowerCase()) {
case JAVA:
System.out.println(file.getName());
countCode(file, javaS, javaE, comm);
break;
case XML:
System.out.println(file.getName());
countCode(file, xmlS, xmlE, comm);
break;
case JSP:
System.out.println(file.getName());
countCode(file, xmlS, xmlE, comm, jspS, jspE);
break;
default:
System.out.println("无法解析后缀为" + suffix.toLowerCase() + "的文件");
}
}
/**
* 统计空行、注释行、代码行
* @param file 文件
* @param flags 表长参数,判断标志
* @throws IOException
*/
private static void countCode(File file, String... flags) throws IOException {
BufferedReader br = null;
boolean comment = false;
boolean comment1 = false;
if (flags.length < length) {
return;
}
try {
br = new BufferedReader(new FileReader(file));
String line = "";
try {
while ((line = br.readLine()) != null) {
line = line.trim();
boolean isComment = line.startsWith(flags[2]) || (line.startsWith(flags[0]) && line.endsWith(flags[1]));
if (p.matcher(line).find()) {
whiteLines++;
} else if (line.startsWith(flags[0]) && !line.endsWith(flags[1])) {
commentLines++;
comment = true;
} else if (comment) {
commentLines++;
if (line.endsWith(flags[1])) {
comment = false;
}
} else if (isComment) {
commentLines++;
} else {
if (flags.length == 5 && jspE.equals(flags[flags.length - 1])) {
if (line.startsWith(flags[3]) && !line.endsWith(flags[4])) {
commentLines++;
comment1 = true;
} else if (comment1) {
commentLines++;
if (line.endsWith(flags[4])) {
comment1 = false;
}
} else if (line.startsWith(flags[3]) && line.endsWith(flags[4])) {
commentLines++;
}
}
normalLines++;
}
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}