GitHub地址:https://github.com/Guyuefangzheng/Word-Count
项目要求
wc.exe 是一个常见的工具,它能统计文本文件的字符数、单词数和行数。这个项目要求写一个命令行程序,模仿已有wc.exe 的功能,并加以扩充,给出某程序设计语言源文件的字符数、单词数和行数。
实现一个统计程序,它能正确统计程序文件中的字符数、单词数、行数,以及还具备其他扩展功能,并能够快速地处理多个文件。
具体功能要求:
程序处理用户需求的模式为:
wc.exe [parameter] [file_name]
基本功能列表:
wc.exe -c file.c //返回文件 file.c 的字符数 (实现)
wc.exe -w file.c //返回文件 file.c 的词的数目 (实现)
wc.exe -l file.c //返回文件 file.c 的行数 (实现)
扩展功能:
-s 递归处理目录下符合条件的文件(实现)
-a 返回更复杂的数据 (实现)
2、psp表
*PSP2.1* | *Personal Software Process Stages* | *预估耗时(分钟)* | *实际耗时(分钟)* |
---|---|---|---|
Planning | 计划 | 60 | 30 |
·Estimate | · 估计这个任务需要多少时间 | 60 | 30 |
Development | 开发 | 1220 | 870 |
· Analysis | · 需求分析 (包括学习新技术) | 150 | 180 |
· Design Spec | · 生成设计文档 | 40 | 20 |
·Design Review | · 设计复审 (和同事审核设计文档) | 40 | 20 |
·Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 20 |
· Design | · 具体设计 | 60 | 60 |
· Coding | · 具体编码 | 400 | 360 |
· Code Review | · 代码复审 | 100 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 200 | 150 |
Reporting | 报告 | 120 | 90 |
· Test Report | · 测试报告 | 60 | 30 |
·Size Measurement | · 计算工作量 | 30 | 30 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 1200 | 990 |
3、解题思路
一开始看到题时想的是用c来实现还是用Java,最后还是选择了熟悉的c。这次的题目涉及到的知识点命令行参数、文件操作这两部分以前没有去深究,因为书都在学校,所以面向搜索引擎来学习这部分的内容。
4、设计实现过程
每一个功能一个函数,再加上一个main函数一共六个函数,在这几个功能模块中WordCount()调用CharCount()来判断该文件是否为空,SearchFile()调用三个基础功能的函数来实现批量操作。
5、代码说明
头文件
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<io.h>
#include<time.h>
基本功能:获取字符数
int CharCount(char *file){ //字符数统计
FILE *fp = NULL;
fp = fopen(file,"r");
if(fp==NULL){
printf("没有找到此文件!
");
exit(-1);
}
int Ccount = 0;
char temp;
while(!feof(fp)){ //文件结束判断
temp = fgetc(fp);
if(temp!=' '&&temp!='
'&&temp!=' '&&temp!=EOF)
Ccount++;
}
fclose(fp);
return Ccount;
}
首先判断该文件是否存在,不存在就退出,不是一个有效字符有四种情况:空格、换行、缩进格、txt文件结束符。
.
基本功能:获取词数
int WordCount(char *file){ //词数统计
if(CharCount(file)==0)
return 0;
int Wcount = 0;
bool b = 0; //用来标记是否是字符
char temp;
FILE *fp = NULL;
fp = fopen(file,"r");
while(!feof(fp)){
temp = fgetc(fp);
if(temp==' '||temp==' '||temp=='
'||temp==EOF){ //四种情况,包括文件结束
if(b==1){ //前面是字符,词数+1
Wcount++;
b = 0;
}
}
else
b = 1; //如果是字符,b标记为1
}
fclose(fp);
return Wcount;
}
通过调用字符统计函数来判断该文件是否存在和是否为空,用一个bool变量来标记,当bool值为1时词数加一。
.
基本功能:获取行数
int LineCount(char *file){ //行数统计
FILE *fp = NULL;
fp = fopen(file,"r");
if(fp==NULL){
printf("没有找到此文件!
");
exit(-1);
}
int Lcount = 1;
char temp;
while(!feof(fp)){
temp = fgetc(fp);
if(temp=='
')
Lcount++;
}
fclose(fp);
return Lcount;
}
行数初始为1,遇到 加1。
.
扩展功能:处理目录下符合条件的文件
int SearchFile(){ //处理目录下符合条件的文件
struct _finddata_t fileinfo; //文件存储信息结构体
long fHandle; //保存文件句柄
int t=0; //文件数记录器
fHandle = _findfirst("*.txt",&fileinfo); //查找当前目录下的txt文件
if(fHandle==-1L)
printf( "当前目录下没有txt文件
");
else
do{
t++;
printf("找到文件:%s
",fileinfo.name);
printf("字符数为:%d
",CharCount(fileinfo.name));
printf("词数为:%d
",WordCount(fileinfo.name));
printf("行数为:%d
",LineCount(fileinfo.name));
}while(_findnext(fHandle,&fileinfo)==0);
_findclose(fHandle); //关闭文件链接
return t;
}
通过头文件io.h中的文件结构体 _finddata_t ,使用 _findfist 和 _findnext 两个函数来查找文件,找到文件,调用基础模块。
.
扩展功能:返回更复杂的数据(代码行 / 空行 / 注释行)
int MoreLine(char *file){ //返回更复杂的数据(代码行 / 空行 / 注释行)
FILE *fp = NULL;
fp = fopen(file,"r");
if(fp==NULL){
printf("没有找到此文件!
");
exit(-1);
}
int nNum = 0,cNum = 0,aNum = 0;
bool b = 0; //
int c;
char temp;
while(!feof(fp)){
temp = fgetc(fp);
if(temp=='
'||temp==EOF){ //换行或者文件结束
//在换行或者文件结束时判断出类型
if(c==0) //空行
nNum++;
else if(c==1){ //代码行
cNum++;
c = 0;
}
else{ //注释行
aNum++;
c = 0;
}
}
else if(temp!=' '&&temp!=' '&&temp!='{'&&temp!='}'){
//判断出代码行和注释行,剩下的即是空行
if(temp=='/'){
if(c==0&&b==0)
b = 1;
else if(c==0&&b==1){
c = 2;
b = 0;
}
}
else if(c!=2)
c = 1;
}
}
fclose(fp);
printf("空行数为:%d
",nNum);
printf("代码行数为:%d
",cNum);
printf("注释行数为:%d
",aNum);
return nNum+cNum+aNum;
}
//设置两个标记变量,一个整形变量用0,1,2来标记该行是空行、代码行还是注释行,一个bool变量用来判断注释行。标记所有的代码行和注释行,剩下的就都是空行了。
.
main函数
int main(int argc,char *argv[]){
clock_t start_t,finish_t;
double Total_time;
start_t = clock();
if(!strcmp(argv[1],"-c"))
printf("charnumber: %d
",CharCount(argv[2]));
else if(!strcmp(argv[1],"-w"))
printf("wordnumber: %d
",WordCount(argv[2]));
else if(!strcmp(argv[1],"-l"))
printf("linenumber: %d
",LineCount(argv[2]));
else if(!strcmp(argv[1],"-s"))
printf("find txt number: %d
",SearchFile());
else if(!strcmp(argv[1],"-a"))
MoreLine(argv[2]);
else{
printf("请输入正确的指令!
");
exit(1);
}
finish_t = clock();
Total_time = (double)(finish_t - start_t) / CLOCKS_PER_SEC;//将时间转换为秒
printf("%f seconds
",Total_time);
}
用头文件time.h中的 clock_t 函数来计算时间。
6、测试运行
7、项目小结
1、这次项目暴露出了我其实对c语言还只是处于最基础的了解,文件操作、时间函数都不熟悉,都是现找现做的,需要加深学习
2、没能对项目的完成时间有个正确的预估,对如何估算PSP的时间还需学习
3、查资料的时候注意到一点,feof(FILE *fp)如果文件结束,则返回非0值,否则返回0,但是读完最后一个字符后,fp->flag仍然没有被设置为_IOEOF,因为还有个文件结束符,直到再次调用fgetc(),feof()才能探测到文件结尾。并且不应用EOF来代替feof(),因为fgetc()返回-1时有两种情况:读到文件结尾或是读取错误。