wordcount

github项目地址:https://github.com/hellostronger/personalWork

具体项目要求

WordCount

  • 实现一个简单而完整的软件工具(源代码特征统计程序)
  • 进行单元测试、回归测试、效能测试,在实现上诉程序的过程中使用相关工具
  • 进行个人软件过程(psp)的实践,逐步记录自己在每个软件工程花费的时间

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 返回更复杂的数据(代码行 / 空行 / 注释行)。

空行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。

代码行:本行包括多于一个字符的代码。

注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:

} //注释

在这种情况下,这一行属于注释行。

高级功能:

-x 参数。这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。

需求举例:
  wc.exe -s -a *.c

返回当前目录及子目录中所有*.c 文件的代码行数、空行数、注释行数。

困难描述

  • 对文件操作陌生
    通过看书理一遍文件相关操作,最后得到了解决,因为c的文件操作课堂上略微带过,所以一直是弱项,通过这次项目,巩固了一遍c的文件操作。

  • 对命令行操作陌生
    一开始看到命令行输入感到恐惧,后来才发现其实跟普通函数一样,只不过在main传进参数,进而,我理解了Linux平常的一些终端操作的背后也是普通的一个个函数,对我学习终端操作产生了帮助。

  • 编写可视化界面不懂如何下手
    当第一次接触项目要求的时候,看见可视化界面心里面想到的是java,但看到了项目举例中的.exe后缀,心里面想到了c,故最后选择了c,埋下了伏笔,最后安排两天时间进行可视化界面要求的完成,通过摸索后来发现c编写可视化界面门槛高,最终几番尝试,失败。

  • 文件操作时遇到的问题
    测试的时候把文件放在桌面目录下,发现进不了第二层,后来发现桌面下文件的图标和在D盘目录下的图标不一样,因为我的代码中使用

if(data.attrib == _A_SUBDIR)

我觉得应该是桌面和D盘的文件夹类别不一致,后来在D盘处测试了,而在处理路径名的时候也因为字符串问题摸索很久

  • 文件的模糊查询
    此处应该使用正则表达式,但是c标准库不支持正则,代码用了取巧办法解决*.c的问题,只支持显示所有.c文件
  • 代码操作
    因为刚开始测试的时候在.txt文件没问题,后来拿.c文件测试发现结果不一样,debug很久,最后做了一些特殊操作把不合理情况消除

部分代码说明

  • main(int i,char *argv[])通过指针数组接收命令行输入的参数,要写参数不符的情况,因为要通过编译,生成.exe文件,将打印放在了主函数中,让子函数只负责计算,比较取巧的是 代码行=总行-注释行-空行
int main(int i,char *argv[]){
   if(i!=3&&i!=2)
   printf("命令错误,格式wc.exe [parameter] [file_name]\n您可输入wc.exe -h 查看相关参数和帮助");
   if(i == 2&&strcmp("-h",argv[1])==0){
   	printf(" -w 返回文件词的数目\n -c 返回文件字符数\n -l 返回文件的行数 \n -s 递归处理目录下符合条件的.c文件\n -a 返回文件详细信息"); 
   }

   else if(i == 3){
   if(strcmp("-c",argv[1])==0){ 
   printf("%s文件中的字符数为%d\n",argv[2], getnum_char(argv[2]));	
   } 
   if(strcmp("-w",argv[1])==0)
   {
   	printf("%s文件中单词数为%d\n",argv[2],getnum_word(argv[2])); 
   }
   if(strcmp("-l",argv[1])==0){
   printf("%s文件中的行数为%d\n",argv[2],getnum_row(argv[2]));
   }
   if(strcmp("-a",argv[1])==0){
   int total,zs,kh,dm; 
   total = getnum_row(argv[2]);
   zs = getnum_zhushirow(argv[2]);
   kh = getnum_null(argv[2]);
   dm = total - zs -kh;
   printf("%s文件中的总行为%d\n",argv[2],total);
   printf("文件中的注释行为%d\n",zs);
   printf("文件中的空行为%d\n",kh) ;
   printf("文件中的代码行为%d\n",dm) ;
   }
   if(strcmp("-s",argv[1])==0){
   	int i = 0;
   	char a[30] = {};
   	while(argv[2][i]!='.'&&argv[2][i+1] != 'c'){
   		a[i] = argv[2][i];
   		i++;
   	}
   	search(a);
   }
   return 0;
   }
} 

  • 只支持*.c情况,能够递归查询子目录下文件
void search(char *path){
	struct _finddata_t data;
	long hnd = _findfirst(path,&data);
	if(hnd < 0 ){
		perror(path);
	}
	int nRet = (hnd<0)? -1:1;
	while(nRet >=0){
		char *nextpath = NULL;
		if(data.name[0]=='.'){
			nRet = _findnext(hnd,&data);
			continue;
		}
		if(data.attrib == _A_SUBDIR){
		nextpath = (char *) malloc ((strlen(path)+strlen(data.name))*sizeof(char));
		char *path2 = (char *) malloc (strlen(path)*sizeof(char));
		for(int i=0;i<strlen(path)-1;i++)
			path2[i] = path[i];
		sprintf(nextpath,"%s%s\\*",path2,data.name);
		free(path2);
		search(nextpath);
		}else{
		for (int i=0;i<strlen(data.name);i++){
			if(data.name[i]=='.'&&data.name[i+1]=='c'){
			char *path3 = (char *) malloc((strlen(path))*sizeof(char));
			for(int i=0;i<strlen(path)-1;i++)
			{
				path3[i] = path[i];
			}
			char *filepath = (char *) malloc ((strlen(path3)+strlen(data.name)+2)*sizeof(char));
			sprintf(filepath,"%s%s",path3,data.name);
			allinformation(filepath);
			free(filepath);
			free(path3);
			}
		}	
		}
		free(nextpath);
		nRet = _findnext(hnd,&data);
	}
	_findclose(hnd);	
}
  • 其它代码
void  allinformation(char f[]){//文件的更多注释 
	int total,zs,kh,dm;  
	printf("%s文件中的字符数为%d\n",f, getnum_char(f));	
	printf("文件中单词数为%d\n",getnum_word(f)); 
	printf("文件中的行数为%d\n",getnum_row(f));
    total = getnum_row(f);
    zs = getnum_zhushirow(f);
    kh = getnum_null(f);
    dm = total - zs -kh;
    
	printf("文件中的总行为%d\n",total);
	printf("文件中的注释行为%d\n",zs);
	printf("文件中的空行为%d\n",kh) ;
	printf("文件中的代码行为%d\n",dm) ;
}
void search(char *path){//找规定目录下.c文件 
	struct _finddata_t data;
	long hnd = _findfirst(path,&data);
	if(hnd < 0 ){
		perror(path);
	}
	int nRet = (hnd<0)? -1:1;
	while(nRet >=0){
		char *nextpath = NULL;
		if(data.name[0]=='.'){
			nRet = _findnext(hnd,&data);
			continue;
		}
		if(data.attrib == _A_SUBDIR){//是目录 
		nextpath = (char *) malloc ((strlen(path)+strlen(data.name))*sizeof(char));
		char *path2 = (char *) malloc (strlen(path)*sizeof(char));
		for(int i=0;i<strlen(path)-1;i++)
			path2[i] = path[i];
		sprintf(nextpath,"%s%s\\*",path2,data.name);
		free(path2);
		search(nextpath);
		}else{//是文件 
		for (int i=0;i<strlen(data.name);i++){
			if(data.name[i]=='.'&&data.name[i+1]=='c'){
			char *path3 = (char *) malloc((strlen(path))*sizeof(char));
			for(int i=0;i<strlen(path)-1;i++)
			{
				path3[i] = path[i];
			}
			char *filepath = (char *) malloc ((strlen(path3)+strlen(data.name)+2)*sizeof(char));
			sprintf(filepath,"%s%s",path3,data.name);//拼接.c文件的路径 
			allinformation(filepath);
			free(filepath);
			free(path3);
			}
		}	
		}
		free(nextpath);
		nRet = _findnext(hnd,&data);
	}
	_findclose(hnd);	
}

int getnum_char(char f[]){//求显示字符数 
	FILE *fp;
	char ch;
	int num = 0;
	fp = fopen(f,"r");
	if(fp==NULL){
		printf("文件读取失败");
		return -1; 
	}
	while((ch=getc(fp))!=EOF){
		if(!isspace(ch)){//把空白符去掉 
			num++;
		}
	}
	fclose(fp);
    return num;
}
	
int getnum_row(char f[]){//总行 
	FILE *fp;
	int num = 0;
	fp = fopen(f,"r");
	if(fp==NULL){
		printf("文件读取失败");
		return -1; 
	}
	if(getnum_char(f)<=0){
		fclose(fp);
		return 0;
	}else{
	char a[100]={};
	while(!feof(fp)){
	fgets(a,100,fp);
	num++;
	}
	fclose(fp);
	return num-1; 
	}
}


int getnum_word(char f[]){//求词数 
	FILE *fp;
	bool flag = true;
	int  ch;
	int num = 0;
	fp = fopen(f,"r");
	while((ch=getc(fp))!=EOF){
		if((ch>='a'&&ch<='z')||(ch<='Z'&&ch>='A')||(ch>='0'&&ch<='9'||ch=='_')){
			if(flag==true){
			num++;
			flag = false;
			}	
		}else{
			flag = true;
		}
	}
	fclose(fp);	
    return num;
} 

  
int getnum_zhushirow(char f[]){//求注释行 
	bool tag = true;
	bool j = false;
	bool end_tag = false;
	FILE *fp;
	int  ch,dh;
	bool flag = false;
	bool duanzhushi = false; 
	bool hangzhushi = false;
	int num = 0;
	fp = fopen(f,"r");
	while((ch=getc(fp))!=EOF){
		if(ch=='/'&&(!duanzhushi||!hangzhushi)){
			flag = true;//读入第一个/ 		 
		}
		if(flag&&j){  //读入第二行 
			if(ch == '*'){ //多段注释
				duanzhushi = true;
			}
			if(ch == '/'){//单行注释 
				hangzhushi = true;
			}
					
		}
		
		if(duanzhushi){
			if(ch =='\n'){
				num++;	
				printf("%d\n",num);
			}
		}
		if(hangzhushi){
			if(ch =='\n'){
				num++;
				hangzhushi=false;
				flag = false;
				j = false;	
			}
		}
		if(ch == '*'&&duanzhushi){
			end_tag = true;
		}
		if(ch == '/'&&end_tag){
			duanzhushi = false;
			end_tag = false;
			flag = false;
			j = false; 
		}	
		if (flag == true)
		j = true;	
	}
	if(hangzhushi)//最后一行注释 
	num++;
	dh = delet(f);
	fclose(fp);
	return num-dh;
	return num;
}


int getnum_null(char f[]){//求空行 
	int num=0;
	FILE *fp;
	if(fp==NULL){
	printf("文件读取失败");
	return -1; 
	}
	fp = fopen(f,"r");
	char a[100];
	if(getnum_char(f)>0){
	while(!feof(fp)){
	fgets(a,100,fp);
	if(a[0]=='\n'||(a[0]=='}'&&a[2]!='/')||(a[0]=='{'&&strlen(a)==2)){//空行情况 
		num++;	
	}
	}
	if(strlen(a)==2&&a[0]=='}')//degbug发现最后没注释时候重复输出,最后作此操作 
	num--;
}
	fclose(fp);
	return num;		
}

int delet(char f[]){
	int num=0;
	FILE *fp;
	if(fp==NULL){
	printf("文件读取失败");
	return -1; 
	}
	fp = fopen(f,"r");
	char a[100];
	if(getnum_char(f)>0){
	while(!feof(fp)){
	fgets(a,100,fp);
	for(int i=0;i<strlen(a)-1;i++){
		if(a[i]=='/'&&a[i+1]=='/'){//即求跟在代码后面行注释 
			if(i>=2)
			num++;
		}
	}
}
}
	fclose(fp);
	return num;	
}

相关操作图片介绍

   由于图片较多,收录在GitHub项目photoshop。doc中
PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 20 15
· Estimate · 估计这个任务需要多少时间 20 15
Development 开发 1240 1800
· Analysis · 需求分析 (包括学习新技术) 180 240
· Design Spec · 生成设计文档 10 0
· Design Review · 设计复审 (和同事审核设计文档) 0 0
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 20 30
· Design · 具体设计 30 30
· Coding · 具体编码 600 700
· Code Review · 代码复审 200 500
· Test · 测试(自我测试,修改代码,提交修改) 200 300
Reporting 报告 45 60
· Test Report · 测试报告 20 20
· Size Measurement · 计算工作量 5 10
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 20 30
合计 1305 1875

总结

这次对个人项目不够重视,该开始规划不够充分,时间安排不够合理,在debug上花费大量时间,总的来说还是基础不够扎实,但是通过这次,让我感受到紧张感,摆正了学习的态度,希望下次能够获得更大的进步。

posted @ 2020-03-16 01:19  胸无、墨  阅读(290)  评论(0)    收藏  举报