思路:因為每個java源文件的內容基本包括java語句、空白行、註釋三部份組成(不包括註解),所以要統計某個文件這三部份的內容各占多少時,隻需寫三個匹配這幾部份內容的正則表達式即可。然後通過IO流讀取文件中的每一行,並根據正則匹配的結果,累加每部份匹配的數量即可。
註釋行:單行註釋(//)、多行註釋、文檔註釋。正則:((//)|(/\\*+)|((^\\s)*\\*)|((^\\s)*\\*+/))+
空白行:一行內隻有空格、\t、\n等非可視字符表示空白行。正則:^\\s*$
代碼行:以分號“;“結束為一行有效的代碼。正則:(?!import|package).+;\\s*(((//)|(/\\*+)).*)*
實現方式:
1、用戶在控制臺輸入要統計的java文件路徑或目錄
2、根據路徑創建一個File對象,判斷文件是否有效,並給出提示。最後將文件和IO流綁定
3、循環讀取文件中的某一行,並根據正則匹配的結果累記每部份匹配的數量
完整代碼如下:
[java]
package regex;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.util.regex.Pattern;
/**
* 代碼統計工具
* 統計某個java源文件或某個目錄中所有java源文件中註釋、空白行、代碼行各占多少行
* 註釋:包括單行註釋(//)、多行註釋、文檔註釋
* 空白行:一行內沒有任何內容的表示空白行
* 代碼行:以分號“;”結束的一條語句,可以統計為一行有效代碼
*/
public class CodeStatDemo {
// 記錄註釋行數
static long annotationLine = 0;
// 記錄空白行數
static long blankLine = 0;
// 記錄有效代碼的行數
static long codeLine = 0;
// 代碼總行數
static long totalLine = 0;
// 文件總數
static long fileCount = 0;
public static void main(String[] args) throws FileNotFoundException {
System.out.println("請輸入要統計代碼量的java文件或java目錄:");
Scanner in = new Scanner(System.in);
String filePath = in.nextLine();
File file = new File(filePath);
// 根據用戶輸入的文件名和目錄執行代碼量統計
codeStat(file);
System.out.println("----------統計結果---------");
System.out.println("文件數量:" + fileCount + "個");
System.out.println(file + "文件/目錄總行數:" + totalLine);
System.out.println("代碼行數:" + codeLine);
System.out.println("註釋行數:" + annotationLine);
System.out.println("空白行數:" + blankLine);
long otherLine = totalLine – (codeLine + annotationLine + blankLine);
System.out.println("其它行數:" + otherLine);
}
private static void codeStat(File file) throws FileNotFoundException {
if (file == null || !file.exists())
throw new FileNotFoundException(file + ",文件不存在!");
fileCount ++; // 文件數累加
if (file.isDirectory()) {
File[] files = file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().endsWith(".java") || pathname.isDirectory();
}
});
for (File target : files) {
codeStat(target);
}
} else {
BufferedReader bufr = null;
try {
// 將指定路徑的文件與字符流綁定
bufr = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
} catch (FileNotFoundException e) {
throw new RuntimeException(file + ",文件不存在!" + e);
}
// 定義匹配每一行的正則匹配器
Pattern annotationLinePattern = Pattern.compile("((//)|(/\\*+)|((^\\s)*\\*)|((^\\s)*\\*+/))+",
Pattern.MULTILINE + Pattern.DOTALL); // 註釋匹配器(匹配單行、多行、文檔註釋)
Pattern blankLinePattern = Pattern.compile("^\\s*$"); // 空白行匹配器(匹配回車、tab鍵、空格)
Pattern codeLinePattern = Pattern.compile("(?!import|package).+;\\s*(((//)|(/\\*+)).*)*",
Pattern.MULTILINE + Pattern.DOTALL); // 代碼行匹配器(以分號結束為一行有效語句,但不包括import和package語句)
// 遍歷文件中的每一行,並根據正則匹配的結果記錄每一行匹配的結果
String line = null;
try {
while((line = bufr.readLine()) != null) {
if (annotationLinePattern.matcher(line).find()) {
annotationLine ++;
}
if (blankLinePattern.matcher(line).find()) {
blankLine ++;
}
if (codeLinePattern.matcher(line).matches()) {
codeLine ++;
}
totalLine ++;
}
} catch (IOException e) {
throw new RuntimeException("讀取文件失敗!" + e);
} finally {
try {
bufr.close(); // 關閉文件輸入流並釋放系統資源
} catch (IOException e) {
throw new RuntimeException("關閉文件輸入流失敗!");
}
}
}
}
}
測試結果:
作者:xyang81