第三次作业 WordCount
第三次作业 WordCount
合作者:201631062403 , 201631062503
GiuHub地址:https://github.com/wangjiajia1225/WangjiaDM
本次作业的链接地址:https://edu.cnblogs.com/campus/xnsy/Test/homework/2203
一、项目要求
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的相关命令。
同过此次实验,我们体验了软件程序的测试过程,认识到了自己在这方面的一些不足,并为以后的进步做出有计划的引导。整个过程中,我们的学习生活都十分充实,我希望以后还能有机会体验这种项目开发过程。