一、开头
(1)合作者:201631107110,201631083416
(2)代码地址:https://gitee.com/zhaoxiaoqin/WordCount.git
(3)本次作业链接地址:https://www.cnblogs.com/zhaoxiaoqin/articles/9824449
二、正文
1.项目完成情况:
1.1 基本功能(完成)
wc.exe -c input.c //返回文件 file.c 的字符数
wc.exe -w input.c //返回文件 file.c 的单词总数
wc.exe -l input.c //返回文件 file.c 的总行数
1.2 扩展功能(未完成)
wc.exe -s //递归处理目录下符合条件的文件
wc.exe -a input.c //返回更复杂的数据(代码行 / 空行 / 注释行)
wc.exe -e stopList.txt // 停用词表,统计文件单词总数时,不统计该表中的单词
[file_name]: 文件或目录名,可以处理一般通配符
2.实现代码
2.1 main函数实现参数传递
1 int main(int argc, char* argv[]) { 2 Test(argc, argv);//测试 3 getchar(); 4 return 0; 5 }
2.2 GetOption函数实现参数解析
1 int *GetOptions(int argc,char* argv[]) 2 { 3 /* 返回0代表参数有错 4 * 1 表示读取字母 5 * 3 表示读取单词 6 * 5 表示读取行数 7 * 它们的和代表所要的功能 8 */ 9 10 char* params; 11 for(int i=0;i<argc;i++) 12 { 13 params = argv[i]; 14 if(strcmp("-c",params) == 0) 15 { 16 ret[0] += 1; 17 } 18 else if(strcmp("-w",params) == 0) 19 { 20 ret[0] += 3; 21 } 22 else if(strcmp("-l",params) == 0) 23 { 24 ret[0] += 5; 25 } 26 //启动图形界面,则退出命令行结口 27 28 } 29 if(argc > 3) { 30 params = argv[argc - 2]; 31 if (strcmp("-o", params) == 0 && argv[argc - 1] != NULL) { 32 result = argv[argc - 1]; 33 ret[1] = argc - 3; 34 } 35 else 36 { 37 ret[1]= argc - 1; 38 } 39 }else { 40 ret[1] = argc - 1; 41 } 42 //处理 -o之前缺少输入文件 43 return ret; 44 }
2.3 WordCount函数根据解析的参数执行相应操作
1 void WordCount(int argc,char* argv[]) 2 { 3 list = createlist();//创建单词列表 4 char* fileName; 5 if (argc <= 1) { 6 Help(); 7 exit(0); 8 } 9 GetOptions(argc,argv); 10 fileName = argv[ret[1]]; 11 switch(ret[0]) 12 { 13 case 1: 14 ReadChar(fileName); 15 break; 16 case 3: 17 ReadWord(fileName); 18 break; 19 case 5: 20 Readlines(fileName); 21 break; 22 case 4: { 23 ReadChar(fileName); 24 flag = 1; 25 ReadWord(fileName); 26 break; 27 } 28 case 6: { 29 ReadChar(fileName); 30 flag = 1; 31 Readlines(fileName); 32 break; 33 } 34 case 8:{ 35 ReadWord(fileName); 36 flag = 1; 37 Readlines(fileName); 38 break; 39 } 40 case 9: { 41 CharWordLine(fileName); 42 break; 43 } 44 default: 45 Help(); 46 break; 47 } 48 }
2.4 ReadChar函数实现对文件的字符统计
1 void *ReadChar(char* fileName) 2 { 3 char* feature = "字符数: "; 4 char buf; 5 //int count[1] = {0}; //用来储存字母出现过的次数 6 int sum = 0; 7 FILE* fp = fopen(fileName,"r"); 8 if (fp == NULL) 9 { 10 printf("Fail to open the file!\n"); 11 Help(); 12 exit(-1); 13 } 14 while(!feof(fp)) 15 { 16 buf = fgetc(fp); 17 sum ++; 18 } 19 fclose(fp); 20 int count[1] = {sum}; 21 WriteToFile(fileName,count,1,feature); 22 print(fileName, count, 1, feature); 23 }
2.5 ReadWord实现对文件的单词统计
1 void *ReadWord(char* fileName) 2 { 3 /*在记录单词个数 的时候, 4 * 我们通过统计逗号和空格的个数 5 * 然后通过计算得到单词的个数 6 * 假设每个单词的长度不超过256字母 7 */ 8 9 char *feature = "单词数:"; 10 getwordCount(fileName);//得到文件的单词统计 11 printword(); 12 int sum = 0; 13 for (int i = 0; i < list.count; i++) 14 sum += list.list[i].count;//计算总量 15 int count[1] = { sum }; 16 WriteToFile(fileName, count, 1, feature); 17 return NULL; 18 }
2.6 ReadLine 实现对文件行数的统计
1 void *Readlines(char* fileName) 2 { 3 char buf = '\0'; 4 char* feature = "行数: "; 5 FILE* fp = NULL; 6 fp = fopen(fileName,"r"); 7 if (fp == NULL) 8 { 9 printf("Fail to open the file!\n"); 10 Help(); 11 exit(-1); 12 } 13 int space[1] = {0}; //记录行数 14 while(!feof(fp)) 15 { 16 buf = fgetc(fp); 17 if (buf == 10) //换行符的ASCII码为10 只要找出所有的换行符就好 18 { 19 space[0] ++; 20 } 21 } 22 space[0] ++; //在最后一个行中会把换行符设置为其他字符,随意需要加1 23 WriteToFile(fileName,space,1,feature); 24 print(fileName, space, 1, feature); 25 //关闭文件 26 fclose(fp); 27 }
2.7 WriteToFile函数实现将统计信息存入文件中
1 void WriteToFile(char* fileName,int count[],int Csize,char* feature) 2 { 3 /*fileName 表示读取的文件 4 * count 表示记录的个数 5 * Csize 表示记录数组的大小 6 * feature表示记录的内容 单词或者字母或者行数 7 * flag 表示只写,还是追加模式,0 表示只写,1表示追加 8 */ 9 char *mode = '\0'; 10 if (flag == 1) 11 { 12 mode = "a+"; 13 } 14 else 15 { 16 mode = "w+"; 17 } 18 int index = 0; //记录字符数 19 for(int i=0;i<Csize;i++) 20 { 21 if(count[i] != 0) 22 { 23 index += count[i]; //计算总的单词个数 24 } 25 } 26 FILE *fp = NULL; 27 fp = fopen(result,mode); //将结果写入文件 28 if (fp == NULL) 29 { 30 printf("Failed when writing the count to file\n"); 31 exit(-1); 32 } 33 fprintf(fp,"%s,%s %d\n",fileName,feature,index); //写入文件 34 35 if (list.count > 0) 36 { 37 for (int i = 0; i < list.count; i++) 38 { 39 fprintf(fp, "%s:%d\n", list.list[i].wordstring, list.list[i].count); //写入文件 40 } 41 } 42 fclose(fp); 43 }
2.8 getwordCount函数实现对文件中各单词的分离和统计
1 void getwordCount(char *filename)//得到各单词的个数统计 2 { 3 char data[100];//假设每行最多100个字符 4 FILE* fp = NULL; 5 fp = fopen(filename, "r"); 6 if (fp == NULL) 7 { 8 printf("Fail to open the file!\n"); 9 Help(); 10 getchar(); 11 exit(-1); 12 } 13 while (!feof(fp)) 14 { 15 fscanf(fp, "%s", &data); 16 char str[n]; 17 for (int i = 0; i < n; i++) 18 { 19 str[i] = '\0'; 20 } 21 int len = 0; 22 for (int i = 0; i < strlen(data); i++) 23 { 24 char c = data[i]; 25 if (!issplitchar(c))//若不为单词分隔符 26 { 27 str[len] = c; 28 29 len++; 30 } 31 else//若为单词分隔符且指针不超过字符长度 32 { 33 if (len > 0) 34 { 35 additem(&list, str);//添加 36 } 37 38 for (int i = 0; i < n; i++) 39 { 40 str[i] = '\0'; 41 } 42 len = 0; 43 } 44 } 45 if (len > 0) 46 { 47 additem(&list, str);//添加 48 } 49 } 50 fclose(fp); 51 52 }
2.9 word和wordlist结构体用于保存单词和单词的个数
1 typedef struct word//保存单词信息 2 { 3 char* wordstring;//内容 4 int count;//数量 5 }word; 6 7 typedef struct wordlist//单词列表定义 8 { 9 word *list;//单词列表 10 int count;//单词种类个数 11 }wordlist;
3.互审代码情况
参数 | 功能 |
-w | 统计文件中的单词个数以及各单词的个数并写入输出文件中 |
-l | 统计文件的行数并写入输出文件中 |
-c | 统计文件中的字符个数并写入输出文件中 |
-o | 文件的路径 |
已完成WordCount的基本功能,包括字符计数、行数计数、单词统计等,但在单词统计和行数统计同时存在时,输出文件中的行数会写错位,该版本的WordCount可以接收多个参数,比如-w -c -l等,可以同时存在,而-w参数可以统计文本文件中的各单词的个数并将其保存在输出文件中。
4.静态代码检查情况
利用VisualStudio自带的静态代码检测工具对项目进行代码检测后,结果如下:
在对出现的风险代码进行修改后,对项目进行测试。
5.测试
5.1 测试用例
用例编号 | 输入 | 输出 | 测试结果 |
1 | WordCount.exe -c text.txt | 文件字符数:726 | 通过 |
2 | WordCount.exe -l text.txt | 文件行数:8 | 通过 |
3 | WordCount.exe -w text.txt | 单词种类数:80 | 通过 |
4 | WordCount.exe -c -l text.txt | 文件字符数: :736 | 通过 |
5 | WordCount.exe -c -l -w text.txt | 文件字符数: :736 文件行数:8 | 通过 |
5.2 测试
测试用例1
测试用例2
测试用例3
测试用例4
测试用例5
6.总结
在对项目进行了一系列测试后,发现该项目不存在较大bug,在输入命令参数时,若输入了不合规则的参数,程序会输出提示字符串,但其中的单词统计不能统计诸如I_ptr等带有下划线的单词,可以在后期的改进中,改良分隔字符串检测的算法,该项目的总体思路为:用户在输入参数后,通过main函数的参数传递,将参数传递到GetOption函数中,GetOption函数通过输入参数的个数和种类来解析用户想要执行的命令,并将命令传递到WordCount函数中,对文件执行相应的操作,而在单词统计模块中,该项目自定义了一个结构体来保存单词的字符串和出现次数,当统计函数对文件进行扫描时,每当扫描出一个单词便判断该单词是否在单词列表中,若不在单词列表中则将该单词添加,若在单词列表中则将该单词的次数加1,从而实现了对文件中不同单词的分隔和个数统计。