Github源码地址:https://github.com/Steven-MJ/ITEM
项目要求
-
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 参数。这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。
PSP
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
60 |
80 |
Estimate |
估计这个任务需要多少时间 |
60 |
75 |
Development |
开发 |
300 |
400 |
Analysis |
需求分析 (包括学习新技术) |
30 |
60 |
Design Spec |
生成设计文档 |
30 |
20 |
Design Review |
设计复审 (和同事审核设计文档) |
30 |
30 |
Coding Standard |
代码规范 (为目前的开发制定合适的规范) |
30 |
40 |
Design |
具体设计 |
60 |
60 |
Coding |
具体编码 |
300 |
400 |
Code Review |
代码复审 |
60 |
50 |
Test |
测试(自我测试,修改代码,提交修改) |
60 |
200 |
Reporting |
报告 |
120 |
80 |
Test Report |
测试报告 |
60 |
40 |
Size Measurement |
计算工作量 |
30 |
30 |
Postmortem & Process Improvement Plan |
·事后总结, 并提出过程改进计划 |
30 |
50 |
合计 |
|
|
解题思路
- 实现基本功能分为统计行数函数、统计字符函数、统计单词行数、主函数部分
- 行数判断主要依靠换行符判断,单词数是以下划线或字母或数字连续组合在一起视作一个单词,碰见非以上三种情况,词数+1,读取下一位,字符函数通过逐一读取字符排除EOF计算得知
- 扩展功能在一自定义函数内实现代码行、空行、注释行的计算
- 空行判断:当行中仅有换行符空格以及行中仅有一可显示字符‘{’‘}’
- 注释行判断:行注释//以及块注释/* 读取/和*起始,到第二个/或*结束,此外单引号和双引号内的内容可能会对判断造成影响,需要过滤掉
- 代码行判断:排除空行、注释行之外剩下的即代码行。
程序设计流程
代码说明
主函数:通过主函数接受外部参数,argc: 整数, 为传给main()的命令行参数个数,argv是一个指针数组,它的每个元素都是一个字符指针,数组的末尾是一个NULL指针。对所给的文件进行相应的计数操作,相应技术操作通过调用自定义函数完成
int main(int argc,char *argv[]) //main函数接受外部参数 { char a1[80],a2[80]; int i; FILE *p; if(argc == 3) { p = fopen(argv[2],"r"); if(p == NULL) { printf("Reading ERROR\n"); printf("请按enter继续"); _getch(); exit(0); } strcpy(a2,argv[2]); strcpy(a1,argv[1]); for(i = 0;a1[i]!='\0';i++) { if(a1[i] == 'l') statisticline(a2); else if(a1[i] == 'a') Muiltiple(a2); else if(a1[i] == 'c') statisticch(a2); else if(a1[i] == 'w') statisticword(a2); else continue; } } else printf("Warning:Please input three parameters"); return 0; }
功能函数:获取行数
通过读取换行符来进行行数的判断
int statisticline(char a2[80]) //统计行数 { char temp; int lines = 0; fp = fopen(a2,"r"); temp = fgetc(fp); while(temp != EOF) { if(temp == '\n') //遇到换行符行数+1 lines++; temp = fgetc(fp); } lines++; printf("LINES are %d in total",lines); fclose(fp); return 1; }
功能函数:获取单词数
由连续的字母数字下划线所组成的视为单词,单个字母也是单词
int statisticword(char a2[80]) //统计单词数 { char temp; int words = 0; fp = fopen(a2,"r"); temp = fgetc(fp); while (temp != EOF) //连续的数字字母下划线组成的视为单词,单个字母也算作单词 { if ((temp >= 'a'&&temp <= 'z') || (temp >= 'A'&&temp <= 'Z') || (temp >= '0'&&temp <= '9')) { while ((temp >= 'a'&&temp <= 'z') || (temp >= 'A'&&temp <= 'Z') || (temp >= '0'&&temp <= '9') || temp == '_') { temp = fgetc(fp); } words++; temp = fgetc(fp); } else temp = fgetc(fp); } printf("WORDS are %d in total",words); fclose(fp); return 1; }
功能函数:获取字符数
int statisticch(char a2[80]) //统计字符数 { char temp; int chara = 0; fp = fopen(a2,"r"); temp = fgetc(fp); while(temp != EOF) { chara++; temp = fgetc(fp); } printf("CHARACTERS are %d in total",chara); fclose(fp); return 1; }
功能函数:获取代码行、空行、注释行
空行判断:当行中仅有换行符以及行中仅有一可显示字符‘{’‘}’。注释行判断:行注释//以及块注释/* 读取/和*起始,到第二个/或*结束,此外单引号和双引号内的内容可能会对判断造成影响,需要过滤掉。代码行判断:排除空行、注释行之外剩下的即代码行。
int Muiltiple(char a2[80]) //综合统计函数,包括代码行,空行,注释行 { char temp; char *a3 = a2; int k = strlen(a2); fp = fopen(a2, "r"); *(a3 + k - 1) = '\0'; int c = 0, e = 0, n = 0; if ( fp== NULL) //判空,读入文件失败 { printf("file read failure."); exit(0); } //fgetc()会返回读取到的字符,若返回EOF则表示到了文件尾,或出现了错误。 temp = fgetc(fp); while (temp != EOF) { if(temp == '\''||temp == '\"')
//过滤掉单引号和双引号之间的内容 ,以免对判断造成干扰 { temp = fgetc(fp); while(temp != '\''||temp != '\"') { temp = fgetc(fp); } } if (temp == '{' || temp == '}') //空行判断 { temp = fgetc(fp); if(temp == '\n') { e++; temp = fgetc(fp); } } else if (temp == '\n') { temp = fgetc(fp); while (temp == '\n') { e++; temp = fgetc(fp); } } else if (temp == '/') //注释行判断 区分行注释和块注释 { temp = fgetc(fp); if (temp == '/') { while (temp != '\n') { temp = fgetc(fp); } n++; temp = fgetc(fp); } if(temp == '*') { temp = fgetc(fp); while(temp != '*') { temp = fgetc(fp); if(temp = '\n') n++; } n++; } } else //代码行判断 { c++; while (temp != '{'&&temp != '}'&&temp != '\n'&&temp != '/'&&temp != EOF) { temp = fgetc(fp); } } } printf("code line count is :%d.\n", c); printf("empty line count is :%d.\n", e); printf("note line count is :%d.\n", n); fclose(fp); return 1; }
测试运行
空文件 NULL.cpp
test1.c
test2.c 以及test3.c
test4.c
项目小结
- 平时主要是用matlab和R语言来做机器学习数据挖掘上的一些东西,突然有这么一个项目交给我感觉还是有点没适应过来,后来决定用从C语言来写这个项目
- 总体来说实现功能的时候,设计的程序的逻辑结构不够清晰,debug的过程耗费了很大的时间。
- 对于C语言可以说加深了理解有一些知识我也是通过这次实践需要去查资料才获得的
- 对于这样子标准开发流程PSP、设计实现过程、设计文档、开发这一趟,以前没有接触过,感觉确实学到了东西。
- 这个项目写下来还是有不少欠缺,对软件开发的一些技术工具知识掌握程度不够好,仍需要继续学习。
- 对于附加功能递归,图形用户界面未能实现。结束后,应去参考其他同学博文学习。