Github:
https://github.com/whoNamedCody/WordCount
PSP表格
PSP2.1 |
PSP階段 |
預估耗時 (分鍾) |
實際耗時 (分鍾) |
Planning |
計划 |
10 | 15 |
· Estimate |
· 估計這個任務需要多少時間 |
20 | 20 |
Development |
開發 |
180 | 250 |
· Analysis |
· 需求分析 (包括學習新技術) |
10 | 30 |
· Design Spec |
· 生成設計文檔 |
10 | 20 |
· Design Review |
· 設計復審 (和同事審核設計文檔) |
20 | 20 |
· Coding Standard |
· 代碼規范 (為目前的開發制定合適的規范) |
10 | 20 |
· Design |
· 具體設計 |
20 | 20 |
· Coding |
· 具體編碼 |
100 | 150 |
· Code Review |
· 代碼復審 |
20 | 30 |
· Test |
· 測試(自我測試,修改代碼,提交修改) |
50 | 100 |
Reporting |
報告 |
20 | 40 |
· Test Report |
· 測試報告 |
30 | 40 |
· Size Measurement |
· 計算工作量 |
10 | 10 |
· Postmortem & Process Improvement Plan |
· 事后總結, 並提出過程改進計划 |
5 | 15 |
合計 |
515 | 780 |
需求說明:
WordCount的需求可以概括為:對程序設計語言源文件統計字符數、單詞數、行數,統計結果以指定格式輸出到默認文件中,以及其他擴展功能,並能夠快速地處理多個文件。
1、基礎功能:
-c:輸出字符,
-l:輸出代碼行,
-w:輸出單詞,
-o:輸出
2、 擴展功能:
-a:輸出代碼行/空行/注釋行,
-s:遞歸處理文件,
-e:停用詞表,
解題思路:
1、java實現,但需要轉成exe在cmd下輸入命令執行,所以流程是:編碼(.java)-->Export(.jar)-->exe4j(.exe)
2、java里有static void main(String[] args),里面的args就是cmd下的命令數組,比如輸入-c -l -w file.c(空格隔開),那么args數組長度為4
3、對args數組進行遍歷分析,找出輸入命令和文件名,比如-c -l -w -a 后面跟的是輸入文件名,-s后面會跟*.c之類的通配文件,-e后面會跟停用詞表stoplist.txt,-o接輸出文件result.txt
這里識別出命令和文件后,會再對文件分析,比如-s ./WordCount/*.c,需要截取出文件的上一層(相對)路徑./WordCount和后綴.c,方便后續遞歸文件夾下的.c文件
4、將所有的統計封裝成一個函數:public void command(String[] args,String inputFile,String outputFile,WordCount WC)
5、創建一個WordCount類,里面的屬性有字符數,單詞數,行數,代碼行,空行,注釋行,如果沒有出現-s:則只實例化一個對象WordCount,調用一次command函數,輸出前面的結果,如果出 現 -s:即遞歸處理文件夾下面的*.c文件(當然*.txt,*.doc文件也是可以的),就聲明多個WordCount對象,循環對對象屬性進行賦值。如果需要輸出就調用get和set方法獲取屬性值。
6、遞歸處理文件:根據相對路徑遞歸尋找文件夾下的后綴文件。
程序設計實現:
類:
public class WordCount{}
函數方法設計:
WordCount(int,int,int,int,int,int)是構造函數;get和set是MyEclipse自動生成的的getter和setter方法,main(string [ ])是程序入口,分析判斷指令格式;command(String [ ],String,String,WordCount)執行指令,返回相應指令的統計值;wc(String,String)對輸入文件進行統計;inStop(String,String[ ])判斷單詞是否在停用詞表內;getFile(File)遞歸獲取文件。
代碼說明:
1、執行命令:需要輸出的有-c,-w,-l,-a,判斷指令,直接暴力循環,優化日后再說。
1 //命令執行,根據命令輸出數據到屏幕和outputFile中 2 public void command(String[] args,String inputFile,String outputFile,WordCount WC)throws IOException{ 3 String outResult=""; 4 inputFile=inputFile.substring(inputFile.lastIndexOf("\\")+1, inputFile.length()); 5 for(int i=0;i<args.length;i++){ 6 if(args[i].equals("-c")) 7 outResult=outResult+inputFile+",字符數:" + WC.getCharCount()+"\r\n"; 8 } 9 for(int i=0;i<args.length;i++){ 10 if(args[i].equals("-w")) 11 outResult=outResult+inputFile+",單詞數:" + WC.getWordCount()+"\r\n"; 12 } 13 for(int i=0;i<args.length;i++){ 14 if(args[i].equals("-l")) 15 outResult=outResult+inputFile+",行數:" + WC.getLineCount()+"\r\n"; 16 } 17 for(int i=0;i<args.length;i++){ 18 if(args[i].equals("-a")) 19 outResult=outResult+inputFile+",代碼行/空行/注釋行:"+WC.getCodeCount()+"," 20 +WC.getSpaceCount()+","+WC.getNoteCount()+"\r\n"; 21 } 22 //寫數據到outputFile 23 System.out.println(outResult); 24 File writename = new File(outputFile); 25 writename.createNewFile(); 26 BufferedWriter out = new BufferedWriter(new FileWriter(writename,true)); 27 out.write(outResult); 28 out.flush(); 29 out.close(); 30 }
2、統計功能字符數、單詞數、行數、代碼行/空行/注釋行
提一下代碼行/空行/注釋行
1 //統計功能字符數、單詞數、行數、代碼行/空行/注釋行 2 public void wc(String inputFile,String stopFile) throws IOException{ 3 String lineString = null; 4 String[] buffer=null; //文件每行 5 String[] buffer1 = null;//stoplist 6 7 boolean isNote = false; 8 int notNote=0; 9 10 //讀取停用詞表 11 if(useStop){ 12 File dirr=new File(stopFile); 13 BufferedReader bff = new BufferedReader(new FileReader(dirr)); 14 while((lineString=bff.readLine())!=null){ 15 buffer1=lineString.split(",| "); 16 } 17 bff.close(); 18 } 19 lineString = null; 20 21 // 讀取輸入文件inputFile 22 File dir=new File(inputFile); 23 BufferedReader bf = new BufferedReader(new FileReader(dir)); 24 while((lineString=bf.readLine())!=null){ 25 26 //遇到 , 空格 就結束賦值 27 buffer=lineString.split(",| "); 28 for(int i=0;i<buffer.length;i++){ 29 30 //使用停用詞表則剔除詞表內單詞,不用則不踢 31 if(useStop){ 32 if(!buffer[i].equals("")&&!inStop(buffer[i], buffer1)){ 33 wordCount++; 34 } 35 } 36 else{ 37 wordCount++; 38 } 39 40 } 41 if(buffer.length!=1) 42 lineCount++; 43 44 charCount+=(lineString.length()+1); 45 46 47 lineString=lineString.trim(); 48 //空行,一個字符的也算空行 49 if (lineString.matches("^[//s&&[^//n]]*$")||lineString.length()==1) { 50 spaceCount++; 51 } 52 //注釋/*的開始 53 else if (lineString.startsWith("/*") && !lineString.endsWith("*/")||((lineString.startsWith("{/*") 54 ||lineString.startsWith("}/*"))&&!lineString.endsWith("*/"))){ 55 noteCount++; 56 isNote=true; 57 } 58 //沒有遇到*/ 59 else if(isNote&&!lineString.endsWith("*/")&&!lineString.startsWith("*/")) { 60 notNote++; 61 noteCount++; 62 } 63 //遇到*/ 64 else if (isNote == true && (lineString.endsWith("*/")||lineString.startsWith("*/"))) { 65 noteCount++; 66 isNote=false; 67 } 68 //注釋行 69 else if (lineString.startsWith("//")|| lineString.startsWith("}//")||lineString.startsWith("{//")|| 70 ((lineString.startsWith("{/*") ||lineString.startsWith("}/*")||lineString.startsWith("/*")) 71 && lineString.endsWith("*/"))) { 72 noteCount++; 73 } 74 else{ 75 codeCount++; 76 } 77 } 78 bf.close(); 79 noteCount-=notNote; 80 codeCount+=notNote; 81 }
1 //判斷是否在停用詞表內 2 public static boolean inStop(String str,String[] buffer){ 3 int count=0; 4 for(int i=0;i<buffer.length;i++){ 5 if(str.equals(buffer[i])){ 6 count++; 7 } 8 } 9 if(count>0) 10 return true; 11 else 12 return false; 13 }
4、遍歷文件目錄,如-s ./test/*.c則遞歸遍歷./test目錄下的.c文件
1 //遍歷目錄文件 2 public static List<File> getFile(File dir) { 3 List<File> files = new ArrayList<File>(); 4 // 此文件下的所有文件和文件夾集合 5 File[] subs = dir.listFiles(); 6 for (File file : subs) { 7 if (file.isFile() && file.getName().endsWith(endStr)) { 8 // 把獲取到的后綴文件添加到集合中,可以是任何后綴文件 9 files.add(file); 10 } else if (file.isDirectory()) 11 //如果是目錄,就進行遞歸 12 files.addAll(getFile(file)); 13 } 14 return files; 15 }
測試設計過程:
設計測試用例的思路是采用白盒測試的語句覆蓋,盡可能把測試用例覆蓋所有可能的程序語句,當然特別是分支語句,會多做測試,如-s的是否遞歸處理文件在我的程序中是一個分支語句
基本功能:
1、測試-c:輸出file.c字符數
wc.exe -c file.c
2、測試-c、-w、-l:輸出file.c字符數,單詞數、行數 (當前根目錄)
wc.exe -c -w -l file.c
3、測試-w 、-l 、-c:輸出./testFile/file.c 字符數,單詞數、行數 (根目錄下其他路徑,命令順序)
wc.exe -w -l -c ./testFile/file.c
4、測試-c 、-l 、-w、-o:輸出file.c字符數,單詞數、行數、輸出到文件resultAdd.txt
wc.exe -c -l -w file.c -o resultAdd.txt
擴展功能:
5、測試-a:輸出file.c的代碼行/空行/注釋行
wc.exe -a file.c
6、測試-s、-a:輸出根目錄下所有.c文件的代碼行/空行/注釋行
wc.exe -s -a *.c
7、測試-e:測試停用詞表stoplist.txt
wc.exe -w file.c -e stoplist.txt
8、測試-c、-w、-l 、-a、-o:輸出file.c字符數,單詞數、行數 、代碼行/空行/注釋行輸出到result.txt
wc.exe -c -w -l -a file.c -o result.txt
9、測試-a、-s、-e:測試遞歸,代碼行/空行/注釋行,停用詞表stoplist.txt
wc.exe -a -s ./testFile/*.c -e stoplist.txt
10、測試-c、-w、-l、-a、-e、-o:對不遞歸進行測試
wc.exe -c -w -l -a file.c -e stoplist.txt -o result.txt
11、測試-c、-w、-l、-a、-s、-e、-o:覆蓋所有的指令測試
測試腳本
點擊testScript.exe可以執行完11個測試用例,類似於批處理的方式,但只有一個進程,批處理測試用例。
下面是java代碼,簡單敘述一下思路:創建一個進程打開之前的wc.exe,逐行讀取測試用例testCase.txt,一行是一條測試用例。
1 package test; 2 import java.io.BufferedInputStream; 3 import java.io.BufferedReader; 4 import java.io.File; 5 import java.io.FileReader; 6 import java.io.IOException; 7 import java.io.InputStreamReader; 8 import java.util.Scanner; 9 10 public class TestScript { 11 //進程p 12 static Process p; 13 public static void main(String[] args) throws IOException{ 14 String lineString=null; 15 File dirr=new File("testCase.txt"); //測試用例文件 16 if(dirr.exists()){ 17 BufferedReader bff = new BufferedReader(new FileReader(dirr)); 18 while((lineString=bff.readLine())!=null){ 19 //非空行執行測試用例 20 if(!lineString.trim().matches("^[//s&&[^//n]]*$")){ 21 System.out.println(lineString); 22 command(lineString); 23 } 24 } 25 bff.close(); 26 }else{ 27 System.out.println("沒有該測試文件"); 28 } 29 30 Scanner sc = new Scanner(System.in); 31 String scc=sc.nextLine(); 32 } 33 34 public static void command(String cmd){ 35 Runtime run = Runtime.getRuntime();//返回與當前 Java 應用程序相關的運行時對象 36 try { 37 p = run.exec(cmd);// 啟動另一個進程來執行命令 38 BufferedInputStream in = new BufferedInputStream(p.getInputStream()); 39 BufferedReader inBr = new BufferedReader(new InputStreamReader(in)); 40 String lineStr; 41 while ((lineStr = inBr.readLine()) != null) 42 System.out.println(lineStr); 43 if (p.waitFor() != 0) { 44 if (p.exitValue() == 1) 45 System.err.println("命令執行失敗!"); 46 } 47 inBr.close(); 48 in.close(); 49 } catch (Exception e) { 50 e.printStackTrace(); 51 } 52 } 53 54 }
參考鏈接: