1. 程式人生 > >第三次作業 WordCount

第三次作業 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的相關命令。

同過此次實驗,我們體驗了軟體程式的測試過程,認識到了自己在這方面的一些不足,併為以後的進步做出有計劃的引導。整個過程中,我們的學習生活都十分充實,我希望以後還能有機會體驗這種專案開發過程。