第三次作業 WordCount
第三次作業 WordCount
合作者:201631062403 201631062503
GiuHub地址:https://github.com/wangjiajia1225/WangjiaDM
一、專案要求
WordCount是一個計數的軟體,它可以統計文字檔案的字元數、單詞數以及行數,還有一些拓展功能:包括遍歷所有的檔案、記錄更復雜的資料(程式碼行/空行/註冊行)、支援萬用字元(*,?)。因為我們都比較熟悉c語言,所以是用C語言編寫的,相互該起來更加的方便。
二、專案實現的功能
3.1.1基本功能(完成)
統計file.c的字元數(實現)
統計file.c的單詞數(實現)
統計file.c的行數(實現)
3.1.2拓展功能(完成)
遞迴處理目錄下符合型別的檔案(實現)
顯示程式碼行、空行和註釋行的行數(實現)
支援萬用字元(* , ?)(實現)
3.1.3高階功能(未完成)
3.1.4定義
字元:可顯示的ASCII碼字元,因此不包括空格和‘\n’等控制字元
單詞:由一串連續英文字母組成,遇到英文以外為單詞的分隔
行:每行以分行符或結束符為標誌,分為三種:
空行:本行只由非顯示字元組成,若有程式碼,則不超過一個可顯示字元
程式碼行:本行包括多於一個字元的程式碼
註釋行:本行不是程式碼行,且包括註釋
三、PSP表格
psp階段 |
估計耗時(時) |
實際耗時(時) |
總體計劃 |
0.5h |
0.6h |
預計完成這個專案時間 |
20h |
24h |
程式開發 |
10h |
15h |
· 需求分析 |
3h |
1h |
· 生成設計文件 |
1h |
0.5h |
· 設計複審 (和同事稽核設計文件) |
1h |
1h |
· 程式碼規範 (為目前的開發制定合適的規範) |
0.5h |
0.5h |
· 具體設計 |
1h |
1h |
· 具體編碼 |
10h |
10h |
· 程式碼複審 |
1h |
1h |
· 測試(自我測試,修改程式碼,提交修改) |
2h |
2h |
報告 |
1h |
1h |
· 測試報告 |
0.5h |
0.5h |
· 計算工作量 |
0.5h |
0.5h |
· 事後總結, 並提出過程改進計劃 |
0.5h |
1h |
合計 |
22h |
20h |
四、解題的思路
解決這個題主要是要實現幾個功能:遍歷文件找到需要開啟的文件進行查詢、統計字元、統計單詞、統計行數、統計特殊函式。分別將這幾個功能寫到不同的函式裡面,然後在主函式裡面進行呼叫,實現這個整個專案的實現。
五、具體程式碼
主要程式碼:
1 int CodeCount(char *Path) { //計算字元個數 2 FILE *file = fopen(Path, "r"); 3 assert(file != NULL); //若檔案不存在則報錯 4 char code; 5 int count = 0; 6 while ((code = fgetc(file)) != EOF) //讀取字元直到結束 7 count+= ((code != ' ') && (code != '\n') && (code != '\t')); //判斷是否是字元 8 fclose(file); 9 return count; 10 }
1 int WordCount(char *Path) { //計算單詞個數 2 3 FILE *file = fopen(Path, "r"); 4 assert(file != NULL); 5 6 char word; 7 int is_word = 0; //用於記錄字元是否處於單詞中 8 int count = 0; 9 10 while ((word = fgetc(file)) != EOF) { 11 if ((word >= 'a' && word <= 'z') || (word >= 'A' && word <= 'Z')) { //判斷是否是字母 12 count += (is_word == 0); 13 is_word = 1; //記錄單詞狀態 14 } 15 else 16 is_word = 0; //記錄不處於單詞狀態 17 } 18 fclose(file); 19 20 return count; 21 }
1 int LineCount(char *Path) { //計算行數 2 3 FILE *file = fopen(Path, "r"); 4 assert(file != NULL); 5 6 char *s = (char*)malloc(200 * sizeof(char)); 7 int count = 0; 8 9 for (; fgets(s, 200, file) != NULL; count++); //逐次讀行 10 11 free(s); 12 fclose(file); 13 14 return count; 15 }
1 void AllDetail(char *Path) { //顯示空行, 程式碼行,註釋行 2 3 FILE *file = fopen(Path, "r"); 4 assert(file != NULL); 5 6 char *s = (char*)malloc(200 * sizeof(char));//申請空間 7 int i; 8 int is_codeline = 0; //狀態記錄變數 9 int is_annoline = 0; 10 int AnnoLock = 0; 11 int AnnoFileLock = 0; 12 13 int codecount = 0; 14 int annocount = 0; 15 int blankcount = 0; 16 17 while (fgets(s, 200, file) != NULL) { //逐次取檔案中的行 18 for (i = 0; *(s+i) != '\0'; i++) { 19 20 if ( ( ( *(s+i) >= 'a' && *(s+i) <= 'z') || ( *(s+i) >= 'A' && *(s+i) <= 'Z') ) && AnnoFileLock == 0) {//判斷是否是程式碼行 21 codecount += (is_codeline == 0 && AnnoLock == 0); //進入程式碼行的時候程式碼行加一 22 is_codeline = 1; 23 } 24 25 if ( *(s+i) == '/' && *(s+i+1) == '/' && is_codeline == 0 && AnnoFileLock == 0){ //判斷是否為註釋行 26 annocount++; 27 AnnoLock = 1; 28 } 29 30 if (*(s + i) == '/' && *(s + i + 1) == '*'){ //判斷文件註釋開始 31 AnnoFileLock = 1; 32 annocount -= is_codeline; //註釋在程式碼後不算註釋行,因此減一 33 } 34 35 if (*(s + i) == '*' && *(s + i + 1) == '/') { //判斷文件註釋結束 36 AnnoFileLock = 0; 37 annocount += (*(s + i + 2) == '\n'); //註釋後換行情況 38 } 39 } 40 annocount += AnnoFileLock; //註釋行結束時算作註釋行加一 41 42 blankcount++; //每一行結束計數加一,並清空狀態 43 is_codeline = 0; 44 is_annoline = 0; 45 AnnoLock = 0; 46 } 47 free(s); 48 fclose(file); 49 50 blankcount = blankcount - codecount - annocount; 51 printf("codeline:%d, annoline:%d, blankline:%d\n", codecount, annocount, blankcount); 52 }
1 void Scan(char *Path, char Type) { 2 char *FileName = NULL; 3 char *FileType = NULL; 4 char Temp[30]; //用於暫存改變得字串 5 long Head; 6 struct _finddata_t FileData; 7 int i = 0; 8 9 FileName = Path; 10 while (*(Path + i) != '\0') { //找出檔名和檔案型別的位置 11 if (*(Path + i) == '\\') 12 FileName = Path + i + 1; 13 if (*(Path + i) == '.') 14 FileType = Path + i + 1; 15 i++; 16 } 17 18 strcpy(Temp, FileType);//調整字串 19 *FileType = '*'; 20 *(FileType + 1) = '\0'; 21 22 Head = _findfirst(Path, &FileData); 23 24 strcpy(FileType, Temp);//恢復字串 25 26 do { 27 if ( !strcmp(FileData.name, "..") || !strcmp(FileData.name, ".")) //去除前驅檔案路徑 28 continue; 29 30 if (_A_SUBDIR == FileData.attrib) //是資料夾 31 { 32 strcpy(Temp, FileName); //調整字串 33 for (i = 0; *(FileData.name + i) != '\0'; i++) { 34 *(FileName + i) = *(FileData.name + i); 35 } 36 *(FileName + i) = '\\'; 37 *(FileName + i + 1) = '\0'; 38 strcat(Path, Temp); 39 40 Scan(Path, Type); 41 42 strcpy(FileName, Temp); //恢復字串 43 } 44 else//是檔案 45 { 46 for (i = 0; *(FileData.name + i) != '.'; i++); 47 if (!strcmp(FileData.name + i + 1, FileType)) { //是指定型別的檔案 48 49 strcpy(Temp, FileName); 50 strcpy(FileName, FileData.name); //調整字串 51 52 printf("%s: ", FileData.name); 53 Run(Type, NULL, Path); //將地址及功能傳到啟動函式 54 printf("\n"); 55 56 strcpy(FileName, Temp);//恢復字串 57 } 58 } 59 } while (_findnext(Head, &FileData) == 0); 60 61 _findclose(Head); 62 }
1 void Run(char Type, char Type2, char *Path) { 2 3 switch (Type) { 4 case 'c': printf("code count: %d\n", CodeCount(Path)); break; 5 case 'w': printf("word count: %d\n", WordCount(Path)); break; 6 case 'l': printf("line count: %d\n", LineCount(Path)); break; 7 case 'a': AllDetail(Path); break; 8 case 's': Scan(Path, Type2); break; 9 default: printf("type input error"); break; 10 } 11 }
1 int main(int argc, char *argv[]) { 2 3 char Path[100] = "*.c"; //預設引數 4 char Type = 's'; 5 char Type2 = 'c'; 6 7 if (argv[1]) { //有輸入引數則以輸入為準 8 Type = *(argv[1] + 1); 9 if (Type == 's') { 10 Type2 = *(argv[2] + 1); 11 strcpy(Path, argv[3]); 12 } 13 else 14 strcpy(Path, argv[2]); 15 } 16 17 Run(Type, Type2, Path); //呼叫啟動函式 18 19 printf("\nPress any key to continue"); 20 getchar(); 21 22 return 0; 23 }
六、測試用例
採用等價類劃分法
輸入 |
有效等價類 |
無效等價類 |
讀取檔案命令 |
-c |
除了-c,-w,-l,-a之外的任何輸入 |
-w |
||
-l |
||
-a |
||
-s |
基於等價類劃分法的測試用例:
有效等價類測試:
E:\軟體質量\作業\WordCount>WordCount.exe -c text |
測試所有檔案內容字元數 |
E:\軟體質量\作業\WordCount>WordCount.exe -w text |
測試所有檔案內容單詞數 |
E:\軟體質量\作業\WordCount>WordCount.exe -l text |
測試所有檔案內容行數 |
E:\軟體質量\作業\WordCount>WordCount.exe -a text |
測試所有檔案內容的程式碼行、註釋行和空行 |
E:\軟體質量\作業\WordCount>WordCount.exe -s -a *.c |
測試遍歷檔案 |
無效等價類測試:
E:\軟體質量\作業\WordCount>WordCount.exe -k text2.txt |
type input error |
七、測試的檔案內容以及測試結果
8.1測試的檔案內容
test.c
@@ -1,3 +1,4 @@ /*this is a test file*/ /* @@ -10,7 +11,8 @@ manson ye #include<string.h> int main() { //main method int main() //main method { int i = 100 / 4; printf("hello world");/**/
字元數
單詞數
行數
程式碼行,註釋行,空行
檔案遍歷
八、程式碼互審
我們在瞭解了具體需要實現的功能以及具體的程式碼計劃之後,分別進行了程式碼的編寫,一個寫完了大體的程式碼,一個沒有寫出檔案遍歷的內容,是直接輸入檔名,然後對字數、行數、字元數、程式碼行數等進行統計。進行互審的過程中發現了一些問題:比如只能顯示字元數,不能顯示字母和行數,要寫在一起才能顯示出來,如果分開了就只能顯示第一個。
九、總結
總結:為了完成這次專案開發,我和我的搭檔花費大量精力,通過網上查詢資料和相互交流磨合,完成這次的Word Count開發,網上有很多相關的部落格和程式碼,他們都是通過不同的思維和語言編寫的,由於我平時專案開發經驗少,所以在看每種開發方法都感覺一頭霧水。後來我們還是選擇了自己相對熟悉的C語言完成專案開發。
在這次專案開發中,由於對工具測試較為陌生,我們選擇較為簡單的等價劃分法測試,通過設定測試用例,檢測程式碼是否有誤。在測試過程中,我們多次用到cmd,熟悉了cmd的相關命令。
同過此次實驗,我們體驗了軟體程式的測試過程,認識到了自己在這方面的一些不足,併為以後的進步做出有計劃的引導。整個過程中,我們的學習生活都十分充實,我希望以後還能有機會體驗這種專案開發過程。