1、github地址html
https://github.com/hyt1022/wordcountjava
2、PSP表格git
PSP2.1github |
PSP階段編程 |
預估耗時數組 (分鐘)eclipse |
實際耗時ide (分鐘)函數 |
Planning學習 |
計劃 |
30 |
30 |
· Estimate |
· 估計這個任務須要多少時間 |
30 |
30 |
Development |
開發 |
840 |
1200 |
· Analysis |
· 需求分析 (包括學習新技術) |
60 |
60 |
· Design Spec |
· 生成設計文檔 |
60 |
60 |
· Design Review |
· 設計複審 (和同事審覈設計文檔) |
30 |
30 |
· Coding Standard |
· 代碼規範 (爲目前的開發制定合適的規範) |
30 |
30 |
· Design |
· 具體設計 |
120 |
120 |
· Coding |
· 具體編碼 |
360 |
600 |
· Code Review |
· 代碼複審 |
60 |
60 |
· Test |
· 測試(自我測試,修改代碼,提交修改) |
120 |
240 |
Reporting |
報告 |
160 |
240 |
· Test Report |
· 測試報告 |
100 |
150 |
· Size Measurement |
· 計算工做量 |
30 |
30 |
· Postmortem & Process Improvement Plan |
· 過後總結, 並提出過程改進計劃 |
30 |
60 |
|
合計 |
1030 |
1470 |
3、解題思路介紹
拿到題目後。首先對程序的準備進行了思考。
此次用Java進行編程,選用的編譯器是Myeclipse10,配置的jdk版本是 。由於有一段時間沒有寫java,稍微有些生疏。所以查閱了大二時面向對象程序設計【1】。這本書對於java的基本語法和經常使用類進行了總結和用法指導,深刻淺出。
後面考慮到要生成exe文件,所以在網上查閱瞭如何將java項目打包生成exe文件【2】。
考慮到要將本地項目上傳到github,在網上查閱了用命令行上傳github的方法。【3】
再對程序的實現進行分析。
看到程序很容易就想到去年編譯技術課程。此次的程序也能夠沿用編譯技術的部分的思想。
對於基礎功能。最直接的想法是,經過將須要分析的* .c文件讀入。用一個字符數組進行存儲。對數組從到頭尾掃一遍,在掃的過程當中,分析統計文件的字符,單詞數,行數等。
對於拓展功能。在基礎功能的基礎上,在掃的過程當中考慮更多的因素。對於停用詞表,現將詞表讀入文件,分紅每個停用詞,存入一個動態的字符數組。在掃待測數組時,將讀到的每一個單詞與停用詞表進行比較,統計停用詞的個數。統計代碼行,空行,數據行的基本思路也和基礎功能的一致。可是須要考慮更多的狀態,以分析判斷此行到底屬於哪種類型。
對於基本輸入輸出。輸入方式經過main函數自帶的參數,分析args[],來判斷輸入的指令。輸出則經過輸入的文件名,將輸出結果寫入txt文件。
4、代碼說明


public void analyse(String fileName,String stoplistFile,boolean f5) { Readfile(fileName); if(f5) { ReadStoplist(stoplistFile); } file = fileName; String tempword; String tep = new String(tempchars); int flag = 0;//判斷上一個字符的標誌,用來推斷單詞數是否增長;進入單詞分隔符則爲0,進入可顯示字符則爲1 while(tempchars[p] != '\0') { if(tempchars[p] == '\n') { flag = 0; l++; p++; } else if(tempchars[p] == '\r') { flag = 0; p++; } else if(tempchars[p] == '\t') { flag = 0; p++; } else if(tempchars[p] == ' ') { flag = 0; p++; } else if(tempchars[p] == ',') { flag = 0; p++; } else//若是是可顯示的字符 { if(flag == 0)//若是上一個是單詞分隔符則單詞數加一 { w++; if(f5)//若是有停用詞表則進行分析 { int a=p; while(tempchars[p] != '\n'&&tempchars[p] != '\r'&&tempchars[p] != '\t'&& tempchars[p] != ' '&& tempchars[p] != ','&&tempchars[p]!='\0') { p++; }//將這個單詞的開始位置和結束位置作標記 tempword = tep.substring(a, p);//將這個單詞截取下來 for(int i=0;i<stopword.size();i++)//將單詞與停用詞表進行對比 { if(tempword.equals(stopword.get(i))) { s++; } } p=p-1;//當前p指向單詞間的分隔符,退回到此字符的前兩個 } } flag = 1; p++; } } }
此段代碼的主要邏輯是一個while循環,循環分析每個字符,以及當前對應的的狀態。
讀到每個字符則字符數加一。
讀到每個換行符則行數加一,最後的行數還要加上第一行。
讀到每個可顯示字符,則判斷前一個字符是否是單詞分隔符,若是是則單詞數加一;若是不是則前一個也是可顯示字符,則爲同一個單詞,單詞數不變。若是有停用詞表,則將單詞截取下來和詞表中的單詞進行對比。


public void analyseAddtion() { int i=0; int flag = 1; //此行是否分配 int cflag = 0; //此行是否處於註釋裏 int dflag = 0; // 此行是不是‘*/’的註釋行 int count =0; //每行有效字符計數 while(tempchars[i] != '\0') { if(tempchars[i] == ' '||tempchars[i] == '\t'||tempchars[i] == '\r')//若是是空格一類的直接跳過 { i++; } else if(tempchars[i] == '/') { count++; if(tempchars[i+1] == '/') { if(flag == 1 && count<3 && cflag == 0)//此種狀況可直接判斷爲註釋行 { comment++; flag = 0; } } else if(tempchars[i+1] == '*') { cflag = 1; i++;//跳過一個字符,防止下一個是‘/’的狀況 } i++; } else if(tempchars[i] == '*') { count++; if(tempchars[i+1] == '/') { if(cflag ==1) { cflag = 0; i++;//跳過一個字符,防止下一個是‘*’的狀況 count = 0; dflag = 1; } } i++; } else if(tempchars[i] == '\n')//到每行末尾,若此行沒有分配則根據當前狀態進行分配 { if(flag == 1 && cflag == 0 && dflag == 0 && count<2) { empty++; flag = 0; } if(flag == 1 && cflag == 0 && dflag == 0 && count>1) { code++; flag = 0; } if(flag == 1 && cflag == 1) { comment++; flag = 0; } if(flag == 1 && cflag == 0 && dflag == 1) { comment++; flag = 0; dflag = 0; } count = 0; flag = 1; i++; } else//若是是其餘字符 { count++; if(count > 1 && flag == 1 && cflag == 0)//此種狀況可直接判斷爲代碼行 { code++; flag = 0; } i++; } } //若最後一行沒有分配,會經過當前狀態進行分配 if(flag == 1 && dflag == 1) { comment++; } if(flag == 1 && cflag == 1) { comment++; } if(flag == 1 && cflag == 0 && dflag == 0 && count<2) { empty++; } if(flag == 1 && cflag == 0 && dflag == 0 && count>1) { code++; } }
此段代碼的主要邏輯也是while循環,循環分析每個字符,以及當前對應的的狀態。
若是讀到空格,製表符和回車符,則直接跳過,這個對判斷行沒有影響。
若是讀到’/’,則判斷下一個是否是’/’,若是是且此行沒有肯定是什麼行,並且此行當前的可顯示字符數不超過兩個而且不在註釋範圍內 ,則可判斷是註釋行。若是下一個是’*’,則此行進入註釋範圍內(須要’*/’才能消除此註釋範圍)。
若是讀到’*’,則判斷下一個是否是’/’,若是是,判斷是否在註釋範圍。若是在,退出註釋範圍,將當前可顯示字符數清零,不在則當作兩個可顯示字符便可。
若是讀到‘\n’,到了每行末尾,如此行還沒肯定是什麼行,則根據當前的狀態判斷,便是否在註釋範圍,是不是’*/’的註釋行,是不是空行等。
最後在退出時,也會判斷最後一的狀態,肯定是什麼行。


for(int i=0; i<args.length;i++)//循環判斷每個字符串 { if(args[i].equals("-c")) { func[0] = true; if((i+1) == args.length)//若是此字符串爲最後一個,則不符合格式,下同 { error = true; break; } if(args[i+1].charAt(0) != '-')//若是下一個不是'-'開頭的指令,則默認爲文件名,進行讀取,下同 { i++; filename = args[i]; } } else if(args[i].equals("-w")) { func[1] = true; if((i+1) == args.length) { error = true; break; } if(args[i+1].charAt(0) != '-') { i++; filename = args[i]; } } else if(args[i].equals("-l")) { func[2] = true; if((i+1) == args.length) { error = true; break; } if(args[i+1].charAt(0) != '-') { i++; filename = args[i]; } } else if(args[i].equals("-o")) { func[3] = true; if((i+1) == args.length) { error = true; break; } i++; outputfile = args[i];//'-o'指令後必須接輸出文件名,進行讀取 } else if(args[i].equals("-e")) { func[4] = true; if((i+1) == args.length) { error = true; break; } i++; stoplistfile = args[i];//'-e'指令後必須接停用詞表文件名,進行讀取 } else if(args[i].equals("-a")) { func[5] = true; if((i+1) == args.length) { error = true; break; } if(args[i+1].charAt(0) != '-') { i++; filename = args[i]; } } else if(args[i].equals("-s")) { func[6] = true; if((i+1) == args.length) { error = true; break; } if(args[i+1].charAt(0) != '-') { i++; filename = args[i]; } } else { error = true; break; } }
循環判斷,主函數自帶的參數,是一個字符串數組。由此分析指令。’-c’, ’-w’, ’-l’, ’-a’指令後面若接文件名則是待分析的文件名,進行讀取。‘-o’後接的文件名必然是輸出文件名,’-e’後接的文件名必然是停用詞表。分析後則可獲得程序須要完成哪些功能,並接受到指令中相應的文件名。
5、測試設計過程
經過11個測試用例和13個執行語句來對程序進行測試。每一個測試用例均對於不一樣的功能有所側重,覆蓋了系統能實現的絕大部分功能。根據白盒測試的思想,測試用例能也能覆蓋絕大部分的條件判斷語句。用例中出現換行和文件結尾時容易致使程序高風險,用例的字符數太高引發數組越界也會形成高風險。此測試方案基本能知足對此程序功能測試要求。如下會對每一個測試用例進行闡釋和具體說明。
測試1:
用例:file1.c
用例說明:用於測試字符統計的基本功能,此用例包含了空格和製表符,測試可否正確統計空格即製表符。
執行語句:-c file1.c -o output1.txt
預計輸出:file1.c,字符數:15
測試2:
用例:file2.c
用例說明::用於測試字符統計的基本功能,此用例包含空行,測試可否統計換行字符。
執行語句:-c file2.c -o output2.txt
預計輸出:file2.c,字符數:22
測試3:
用例:file3.c
用例說明:用於測試單詞統計的基本功能,此用例包含換行,空格,逗號隔開,測試可否正確統計單詞數。
執行語句:-w file3.c -o output3.txt
預計輸出:file3.c,單詞數:16
測試4:
用例:file4.c
用例說明:用於測試停用詞表功能,此用例測試基本功能,測試可否將例子中須要屏蔽的單詞屏蔽。
執行語句:-w file4.c -e stoplist.txt -o output4.txt
預計輸出:
file4.c,單詞數:13
file4.c,停用後單詞數:10
測試5:
用例:file5.c
用例說明:用於測試停用詞表功能,此用例包含單詞中含有停用詞表的單詞但不等於此單詞,測試是否會誤判斷屏蔽。
執行語句:-w file5.c -e stoplist2.txt -o output5.txt
預計輸出:
file5.c,單詞數:20
file5.c,停用後單詞數:20
測試6:
用例:file6.c
用例說明:用於測試行統計功能,此用例測試基礎功能,包含空行,只有一個字符的行等。
執行語句:-l file6.c -o output6.txt
預計輸出:file6.c,行數:9
測試7:
用例:file7.c
用例說明:用於測試代碼行和註釋行,此用例包含容易混淆的代碼行和註釋行的狀況,測試可否正確統計行數。
執行語句:-a file7.c -o output7.txt
預計輸出:file7.c,代碼行/空行/註釋行: 6/0/3
測試8:
用例:file8.c
用例說明:用於測試代碼行和空行,此用例包含不少容易混淆的空行和註釋行的狀況,測試是否能正確統計行數。
執行語句:-a file8.c -o output8.txt
預計輸出:file8.c,代碼行/空行/註釋行: 0/1/4
測試9:
用例:file9.c
用例說明:用於測試空行和代碼行,此用例包含容易混淆的代碼行和空行的狀況,測試時候能正確統計行數。
執行語句:-a file9.c -o output9.txt
預計輸出:file9.c,代碼行/空行/註釋行: 2/4/0
測試10:
用例:file10.c
用例說明:用於測試代碼行,空行,註釋行。此用例爲綜合用例,包含各類可能混淆的狀況,測試可否正確統計行數。
執行語句:-a file10.c -o output10.txt
預計輸出:file10.c,代碼行/空行/註釋行: 11/1/16
測試11:
用例:file1.c
用例說明:用來測試在不提供製定輸出文件下,可否將結果輸出在默認文件result.txt中。
執行語句:-l file1.c
預計輸出:file1.c,字符數:15
測試12:
用例:當前文件夾中全部「.c」文件
用例說明:用於測試可否遞歸處理當前文件夾中全部符合條件的文件。
執行語句:-w -s .*.c -o output12.txt
預計輸出:(較多不予以顯示)
測試13:
用例:file11.c
用例說明:用於測試全功能,包含全部的功能指令,給出的用例中也包含了各類可能處理的狀況,測試可否正常運行並給出正確的結果。
執行語句:-c -w -l -a -s *.c -e stoplist.txt -o output13.txt
預計輸出:(較多不予以顯示)
6、參考文獻
【1】面向對象程序設計教程,任宏萍編著。
【2】https://www.cnblogs.com/yxwkf/p/4609765.html
【3】https://jingyan.baidu.com/article/0202781145eaab1bcc9ce5f0.html