个人项目作业
1.Github项目地址:
https://github.com/Dioikawa/SE-wordcount
2.WC项目要求
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 参数。这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。(未实现)
3.实现程序前的对程序各模块开发时间的估计:
|
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
|
Planning |
计划 |
30 |
|
· Estimate |
· 估计这个任务需要多少时间 |
30 |
|
Development |
开发 |
740 |
|
· Analysis |
· 需求分析 (包括学习新技术) |
120 |
|
· Design Spec |
· 生成设计文档 |
10 |
|
· Design Review |
· 设计复审 (和同事审核设计文档) |
20 |
|
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
20 |
|
· Design |
· 具体设计 |
120 |
|
· Coding |
· 具体编码 |
360 |
|
· Code Review |
· 代码复审 |
30 |
|
· Test |
· 测试(自我测试,修改代码,提交修改) |
60 |
|
Reporting |
报告 |
130 |
|
· Test Report |
· 测试报告 |
50 |
|
· Size Measurement |
· 计算工作量 |
50 |
|
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
30 |
|
合计 |
|
900 |
4.解题思路
(1)命令行程序的了解。一开始我对命令行程序并不了解,经过网上查证后,才知道该程序应该要在Dos命令行中运行。
(2)编程语言的选择。由于我之前了解到可以利用Dos命令行对c语言主函数 int main(int argc,char* argv[])中的形参赋值,且方便快捷,因此选择了c语言作为该程序的编程语言。
(3)各个功能模块的实现。经过对wc项目要求有了大致的了解后,我得知要实现程序要求的功能需要掌握对文件输出输入方面的编程知识。因此我利用了不少时间对这方面知识进行了学习。
5.设计实现过程
对项目需求细分后得知需实现7个模块功能(已实现5个),经过编码尝试后,因为各个功能模块相对独立,因此将功能模块分为5个函数来实现。分别是:计算字符数,计算单词数,计算行数,计算空白行数以及计算代码行数。由于一些函数较为复杂,例如计算空白行数和计算代码行数,因此需要利用流程图作大致的描述方便代码的编写。
6.代码说明
(1)用fgetc函数读取文件中的字符并计数
int CharCount(FILE *f) //计算文件的字符数目 -c
{
char c;
int count=0;
while(!feof(f))
{
c=fgetc(f);
if(c!=' '&&c!='\n'&&c!='\t') //若非读取到的非空格回车则判断为字符
count++;
}
fclose(f);
printf("The number of character is %d.\n",count);
return count;
}
(2)利用标记tag作为字母连续出现的标准
int WordCount(FILE *f) //计算文件的词数目 -w
{
char w;
int count=0;
int tag=1; //用于记录文件位置标记是否仍在同一单词内,为0说明仍在,为1说明遇到新单词
while(!feof(f))
{
w=fgetc(f);
if((w>='A'&&w<='Z')||(w>='a'&&w<='z'))
{
if(1==tag) //tag为1,单词数+1,同时tag置0
{
count++;
tag=0;
}
}
else tag=1;
}
fclose(f);
printf("The number of word is %d.\n",count);
return count;
}
(3)由于新建的空文件的行数应该为0,但用通常方法会计算得1,因此需要对文件判断是否为空文件
int LineCount(FILE *f) //计算文件的行数目 -l
{
char l;
int count=0;
fgetc(f);
if(!feof(f)) //判断是否是空白文件,若不为空白文件则行数+1,遇到回车自动+1
{
count++;
rewind(f);
while(!feof(f))
{
l=fgetc(f);
if(l=='\n')
count++;
}
}
fclose(f);
printf("The number of line is %d.\n",count);
return count;
}
(4)同理判断文件是否为空白文件。对空白行的判断为只有不超过一个可显示的字符
int BlankLineCount(FILE *f) //计算空白行
{
char b;
int blankline=0; //统计空白行数
int chcount=0; //统计字符个数
fgetc(f);
if(!feof(f)) //判断是否是空白文件,若为空白文件则行数为0
{
rewind(f);
while(!feof(f))
{
b=fgetc(f);
if(0==chcount)
{
if(b=='\n')
blankline++;
else if(b!=' '&&b!='\t')
chcount++;
}
else if(1==chcount)
{
if(b=='\n')
{
blankline++;
chcount=0;
}
else if(b!=' '&&b!='\t')
chcount++;
}
else
{
if(b=='\n')
chcount=0;
}
}
if(chcount<=1) //判断最后一行是否为空白行
blankline++;
}
fclose(f);
printf("The number of blankline is %d.\n",blankline);
return blankline;
}
(5)计算文件的代码行,对每行的第二个可显示的字符进行判断,若不为‘/’,则判断为代码行而非注释行。
int CodeLineCount(FILE *f) //计算文件的代码行
{
char c;
int codeline=0; //代码行数
int chcount=0; //字符数
while(!feof(f))
{
c=fgetc(f);
if(chcount==0)
{
if(c!='\n'&&c!=' '&&c!='\t')
chcount++;
}
else if(chcount==1)
{
if(c=='\n')
chcount=0;
else if(c=='/')
chcount++;
else if(c!=' '&&c!='\t')
{
codeline++;
chcount++;
}
}
else
{
if(c=='\n')
chcount=0;
}
}
fclose(f);
printf("The number of codeline is %d.\n",codeline);
return codeline;
}
(6)利用Dos命令行对主函数中形参argc和argv[]进行赋值,由输入的模式为wc.exe [parameter] [file_name] 可知 argv[0]为wc.exe argv[1]为 [parameter] argv[2]为[file_name]
int main(int argc,char* argv[]) //在命令行中输入赋予参数具体的值
{
FILE *fp;
int a,b,c;
if((fp=fopen(argv[argc-1],"r"))==NULL){
printf("Please input the correct filename!\n");
exit(0);
}
else if(!strcmp(argv[1],"-c"))
CharCount(fp);
else if(!strcmp(argv[1],"-w"))
WordCount(fp);
else if(!strcmp(argv[1],"-l"))
LineCount(fp);
else if(!strcmp(argv[1],"-a"))
{
a=LineCount(fp);
fp=fopen(argv[argc-1],"r");
b=BlankLineCount(fp);
fp=fopen(argv[argc-1],"r");
c=CodeLineCount(fp);
printf("The number of commentline is %d.\n",a-b-c); //注释行=总行数-代码行-空白行
}
else printf("Please input the correrct parameter!\n");
return 0;
}
7.测试运行
测试文件test1.c
#include<stdio.h>
int main()
{
printf("Hello World!\n");
return 0;
}
运行结果:

测试文件test2.c
#include <stdio.h>
int main(){
return 0;
}
运行结果:

测试文件test3.c
#include<stdio.h> //预编译命令
int main() //主函数
{
printf("Hello World!\n");
return 0;
}//函数结束
运行结果:

8.实际花费时间
|
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
|
Planning |
计划 |
30 |
20 |
|
· Estimate |
· 估计这个任务需要多少时间 |
30 |
20 |
|
Development |
开发 |
740 |
850 |
|
· Analysis |
· 需求分析 (包括学习新技术) |
120 |
150 |
|
· Design Spec |
· 生成设计文档 |
10 |
0 |
|
· Design Review |
· 设计复审 (和同事审核设计文档) |
20 |
0 |
|
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
20 |
20 |
|
· Design |
· 具体设计 |
120 |
90 |
|
· Coding |
· 具体编码 |
360 |
500 |
|
· Code Review |
· 代码复审 |
30 |
60 |
|
· Test |
· 测试(自我测试,修改代码,提交修改) |
60 |
30 |
|
Reporting |
报告 |
130 |
100 |
|
· Test Report |
· 测试报告 |
50 |
30 |
|
· Size Measurement |
· 计算工作量 |
50 |
30 |
|
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
30 |
40 |
|
合计 |
|
900 |
970 |
9.项目小结
在这次个人项目的完成过程中产生了相当多的问题,其中大部分都是代码是设计编写过程中出现漏洞。由于这次个人项目我起步比较晚而且编程能力不强,导致这次项目要求中的扩展功能中的-a参数以及高级功能并没有实现但是我还是获益匪浅,比如对个人项目开发流程有了一定程度的理解以及在开发过程中掌握了不少的新知识。同时通过本次项目开发,也使得我对软件工程这个专业终于有了点模糊的认识,为以后的学习铺平了道路。

浙公网安备 33010602011771号