WordCount项目小结
项目码云地址:
https://gitee.com/SenLinJ/WordCount
1.项目需求
WordCount的需求可以概括为:对程序设计语言源文件统计字符数、单词数、行数,统计结果以指定格式输出到默认文件中,以及其他扩展功能,并能够快速地处理多个文件。
可执行程序命名为:wc.exe,该程序处理用户需求的模式为:
wc.exe [parameter] [input_file_name]
存储统计结果的文件默认为result.txt,放在与wc.exe相同的目录下。
wc.exe -c file.c //返回文件 file.c 的字符数
wc.exe -w file.c //返回文件 file.c 的单词总数
wc.exe -l file.c //返回文件 file.c 的总行数
wc.exe -o outputFile.txt //将结果输出到指定文件outputFile.txt
注意:
空格,水平制表符,换行符,均算字符。
由空格或逗号分割开的都视为单词,且不做单词的有效性校验,例如:thi#,that视为用逗号隔开的2个单词。
-c, -w, -l参数可以共用同一个输入文件,形如:wc.exe –w –c file.c 。
-o 必须与文件名同时使用,且输出文件必须紧跟在-o参数后面,不允许单独使用-o参数。
第一,确保可执行文件的名字统一为 wc.exe。
第二,确保生成的结果文件 result.txt 与可执行文件在同一目录下,生成文件时请使用相对路径!
一个示例组织目录如下所示:
/ WCProject ( 工程名字自行指定即可 )/ *.* (放置源代码,具体目录自行处理)/ BIN / *.*(exe运行需要的依赖库文件) / wc.exe / result.txt (运行exe后生成)
参数及其约定如下:
参数名字 |
参数意义 |
用法示例 |
-c[必选] |
文件的字符数 |
示例:wc.exe -c file.c [表示返回文件file.c的字符数,并存储在result.txt中] |
-w[必选] |
文件单词总数 |
示例:wc.exe -w file.c [表示返回文件file.c的单词数,并存储在result.txt中] |
-l[必选] |
文件行数 |
示例:wc.exe -l file.c [表示返回文件file.c的总行数,并存储在result.txt中] |
-o[必选] |
输出文件名 |
示例:wc.exe –c file.c -o outfile.txt [表示返回文件file.c的字符数,并存储在outfile.txt中] |
在刚看到这个项目的时候,我想到了c语言对于文件处理的内容,所以我就使用c语言来完成了这个项目。同时使用c语言的开源编译工具Mingw中的gcc,并且使用cmake工具实现对源代码的管理。使项目的移植性有所提高。
对于本项目我只是实现最基础的功能,对于扩展和高级的功能并没有实现。因为本项目对于参数的处理是一个最关键的步骤,而我对参数的位置没有要求,仅仅是在对于写入文件的结果具有则按照字符-->单词-->行数-->代码行数/空行数/注释行的顺序,依次分行显示的要求。当有-o参数和指定的输出文件的时候,才将处理好的结果写入到指定的输出文件中,否则输出到和wc.exe 所在的同一目录下的result.txt文件中。
2.PSP表格
PSP2.1 |
PSP阶段 |
预估耗时 (分钟) |
实际耗时 (分钟) |
Planning |
计划 |
20 |
10 |
· Estimate |
· 估计这个任务需要多少时间 |
20 |
10 |
Development |
开发 |
450 |
580 |
· Analysis |
· 需求分析 (包括学习新技术) |
30 |
60 |
· Design Spec |
· 生成设计文档 |
20 |
0 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
10 |
0 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
10 |
0 |
· Design |
· 具体设计 |
30 |
60 |
· Coding |
· 具体编码 |
120 |
250 |
· Code Review |
· 代码复审 |
40 |
0 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
180 |
210 |
Reporting |
报告 |
80 |
90 |
· Test Report |
· 测试报告 |
10 |
20 |
· Size Measurement |
· 计算工作量 |
30 |
20 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
40 |
50 |
|
合计 |
550 |
680 |
PS(总结):
时间的差别主要是编码与测试模块。对于C语言中的一些文件读写有些遗忘,所以就重新去看了一下对于文件操作的一些方面。在测试过程中,不知道如何去构建测试,需要一个一个的输入,然后又通过数组的方式传入参数才使得测试这一过程节约了一部分时间。
3.详细设计
开发环境:
操作系统为window10专业版 ,开发工具为 CLION ,MinGW
将结果写入文件的代码
void WriteToFile(char* fileName,int count[],int Csize,char* feature) { /*fileName 表示读取的文件 * count 表示记录的个数 * Csize 表示记录数组的大小 * feature表示记录的内容 单词或者字母或者行数 * flag 表示只写,还是追加模式,0 表示只写,1表示追加 */ char *mode = '\0'; if (flag == 1) { mode = "a+"; } else { mode = "w+"; } int index = 0; //记录字符数 for(int i=0;i<Csize;i++) { if(count[i] != 0) { index += count[i]; //计算总的单词个数 } } FILE *fp = NULL; fp = fopen(result,mode); //将结果写入文件 if (fp == NULL) { printf("Failed when writing the count to file\n"); exit(-1); } fprintf(fp,"%s,%s %d\n",fileName,feature,index); //写入文件 fclose(fp); }
处理单个字符的代码
void *ReadChar(char* fileName) { char* feature = "字符数: "; char buf; int count[N] = {0}; //用来储存字母出现过的次数 FILE* fp = fopen(fileName,"r"); if (fp == NULL) { printf("Fail to open the file!\n"); Help(); exit(-1); } while(!feof(fp)) { buf = fgetc(fp); count[buf] ++; } fclose(fp); WriteToFile(fileName,count,N,feature); //将结果保存到人间重 }
处理单词的代码
void *ReadWord(char* fileName) { /*在记录单词个数 的时候, * 我们通过统计逗号个数 * 然后通过计算得到单词的个数 * 假设每个单词的长度不超过256字母 */ char* feature = "单词数: "; char buf[N]; FILE* fp = NULL; fp = fopen(fileName,"r"); if(fp == NULL) { printf("Fail to open the file!\n"); Help(); exit(-1); } int dot = 0; //记录逗号的个数 int sum = 0; while(!feof(fp)) { fscanf(fp,"%s",buf); //会读到空格结束,所以不需要来找出空格分开的单词只需要逗号分开的就行 int n = strlen(buf); for(int i=1;i<n;i++) { if(',' == buf[i]) { dot++; } } if(n > 0) { sum += dot +1;//通过逗号计算单词总数 dot = 0; } } int count[1] = {sum}; WriteToFile(fileName,count,1,feature); //关闭文件 fclose(fp); }
处理行数的代码
void *Readlines(char* fileName) { char buf = '\0'; char* feature = "行数: "; FILE* fp = NULL; fp = fopen(fileName,"r"); if (fp == NULL) { printf("Fail to open the file!\n"); Help(); exit(-1); } int space[0] = {0}; //记录行数 while(!feof(fp)) { buf = fgetc(fp); if (buf == 10) //换行符的ASCII码为10 只要找出所有的换行符就好 { space[0] ++; } } space[0] ++;//在最后一个行中会把换行符设置为其他字符,随意需要加1 WriteToFile(fileName,space,1,feature); //关闭文件 fclose(fp); }
4.文件结构
. ├── bin ├── CMakeLists.txt ├── headers │ └── WordCount.h └── src ├── WordCount.c └── main.c
5.测试
在测试的时候,自己随便弄了一些文档,其中有对于代码文件.c的测试,也有对于没有后缀名的文件测试。都是对于ASCII编码文件的测试。
对于二进制文件并没有测试。因为如果使用二进制文件使用普通文件的读写方式一定会导致结果出错。在对于二进制文件这个方面开始并有考虑到,所以也就没有处理。
普通文件和二进制文件在内存中储存方式不一样,所以读写方式也就不一样。有文本方式的读写二进制文件会使读取到的数据乱码。
测试用例
wc.exe -c test.txt
wc.exe -w test.txt
wc.exe -l test.txt
wc.exe -c -w test.txt
wc.exe -l -w -c test.txt
wc.exe -l test.txt -o test
wc.exe -c
wc.exe test.txt
wc.exe -c test.txt -o
测试结果
test.txt
1.
2.
3.
4
5.
6.
7.
8.
9.
在测试情况下项目运行的符合预期,因为测试用例不够多可能仍然有一些bug没有测试出来。
在处理文件的时候,当有多个文件需要处理的时候,默认处理最后一个输入的文件。指定输出文件的时候,默认输出为指定的最后一个文件名。
心得:
通过这一次的项目,不仅仅学到了git的一些命令,还有就是对于软件工程的一些了解。原先对于软件工程的了解仅仅是认为只是要把代码写好就行,但是并不是。写代码只是其中最重要的步骤之一。如果连需求都不知道,那么也就没有办法去写代码,也不知道该写些什么样的代码。在写代码之前也要把概要设计给写一下。当有了概要设计,软件的逻辑结构也就出现了眼前,那么代码也就容易写出来。在写代码的时候就要测试和修改,完成一个功能测试一下,虽然感觉有点厌烦,但是对于bug的修复确是很有帮助的。
参考:
1《程序设计实践教程 》 章小莉 周知杨 张岩 赵耿 编著 清华大学出版社 2012年10月