软件工程第一次作业:个人项目WC
github地址 :https://github.com/zhangabing/First-test-WC
个人项目:WC
1.项目要求
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 返回更复杂的数据(代码行 / 空行 / 注释行)。- 空行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。
- 代码行:本行包括多于一个字符的代码。
- 注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:
- } //注释
- 在这种情况下,这一行属于注释行。
- -s 递归处理目录下符合条件的文件。
-
高级功能:
- -x 参数。这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。
- 需求举例:
- wc.exe -s -a .c
- 返回当前目录及子目录中所有.c 文件的代码行数、空行数、注释行数。
2.遇到的困难及解决方法
主要困难有
- 当双引号出现在注释之中时
- 当注释符出现在双引号或者是单引号之中时
- 当块注释符号出现在行注释符之后时
- 当块注释结束之后进入代码行,但是行末再次出现行注释时
- 某一行既可以是代码行,也可以是注释行,或者既可以是注释行,也可以是空行
一开始并没有考虑到第五点,然后就写出了一次程序,但是在后来听闻同学找了老师问清楚要求之后,整份代码都进行了重新书写,并且判断注释行,代码行,空行比较麻烦,最终使用了几个bool类型标记终于完成这一功能
当我完成上面所述的问题之后,我觉得我的代码实现能力涨了一大截,并且思考是否还有更为极端得情况。
3.关键代码or设计说明
本文实现了基本功能,和扩展功能
先进行文件内容的读取
bool input(FILE * fp)
//读入文本
{
str = "";
char s;
while((s = fgetc(fp)) != EOF)
str = str + s;
str = str + '\n';
if(str.length() == 1)
{
Null = true;
}
return Null;
}
基本功能:直接调用相对应的函数完成
void Line()
//统计行数
{
int num = 0;
for(int i = 0; i < str.length(); i ++)
{
if(str[i] == '\n') num ++;
}
if(!Null)
printf("行数 :%d\n", num);
}
void Char()
//统计字符
{
int num = 0;
for(int i = 0; i < str.length(); i ++)
{
if(str[i] != ' ' && str[i] != '\n' && str[i] != '\t')
num ++;
}
if(!Null)
printf("字符个数 :%d\n", num);
}
void Words()
//统计单词
{
int num = 0;
bool flag = 0;
for(int i = 0; i < str.length(); i ++)
{
if(str[i] <= 'z' && str[i] >= 'a' || str[i] <= 'Z' && str[i] >= 'A' || str[i] == '_')
{
if(!flag) num ++;
flag = true;
}
else flag = false;
}
if(!Null)
printf("单词个数 :%d\n", num);
}
调用calc直接对读入的文件进行统计代码行,注释行,空行
void Calc()
{
bool line_comment = false; //行注释
bool block_comment = false; //块注释标记
bool comment_exist = false; //注释出现过标记
string s_comment = "";
string s_code = "";
//注释里面的字符串和代码里面的字符串
if(str[0] == '\n')
Empty ++;
else if(str[0] != ' ' && str[0] != '\t')
s_code = s_code + str[0];
for(int i = 1; i < str.length(); i ++)
{
if(str[i] == ' ' || str[i] == '\t')
continue ;
if(str[i] == '\n')
{
if(comment_exist || line_comment || block_comment)
Comment ++;
//注释判断
if(s_comment.length() == 0)
{
if(s_code.length() == 0)
Empty ++;
if(s_code.length() == 1 && (s_code[0] == '{' || s_code[0] == '}' || s_code[0] == ';'))
Empty ++;
}
//空行判断
if(s_code.length() > 1 || (s_code[0] != '{' && s_code[0] != '}' && s_code[0] != ';'))
Code ++;
//代码行判断
s_code = "";
s_comment = "";
line_comment = false;
comment_exist = false;
//换行之后初始化
}
else if(line_comment)
//行注释中
{
s_comment = s_comment + str[i];
comment_exist = true;
}
else if(block_comment)
//块注释中
{
s_comment = s_comment + str[i];
comment_exist = true;
if(str[i - 1] == '*' && str[i] == '/')
block_comment = false;
//块注释终止
}
else if(str[i - 1] == '/' && str[i] == '/')
//将代码字符串最后一个 / 保存到注释字符串之中,并行注释标记为真
{
s_code = s_code.substr(0, s_code.length() - 1);
s_comment = s_comment + str[i - 1] + str[i];
line_comment = true;
comment_exist = true;
}
else if(str[i - 1] == '/' && str[i] == '*')
//将代码字符串最后一个 / 保存到注释字符串之中,并块注释标记为真
{
s_code = s_code.substr(0, s_code.length() - 1);
s_comment = s_comment + str[i - 1] + str[i];
block_comment = true;
comment_exist = true;
}
else if(str[i] == '\"')
//读到双引号时,直接循环到下一个双引号, 并保存至代码字符串之中
{
s_code = s_code + str[i];
while(str[++ i] != '\"')
{
s_code = s_code + str[i];
}
s_code = s_code + str[i];
}
else if(str[i] == '\'')
//读到单引号时,直接循环到下一个单引号, 并保存至代码字符串之中
{
s_code = s_code + str[i];
while(str[++ i] != '\'')
{
s_code = s_code + str[i];
}
s_code = s_code + str[i];
}
else
//普通字符
s_code = s_code + str[i];
}
if(!Null)
{
printf("注释行数 : %d\n", Comment);
printf("代码行数 : %d\n", Code);
printf("空行数 : %d\n", Empty);
}
4.测试报告
由于技术有限,笔者采取的是手工测试
第一组测试结果如下:
第二组测试结果如下:
第三组测试结果如下:
第四组测试结果如下:
5.PSP
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 15 | 40 |
· Estimate | · 估计这个任务需要多少时间 | 15 | 40 |
Development | 开发 | 540 | 915 |
· Analysis | · 需求分析 (包括学习新技术) | 180 | 300 |
· Design Spec | · 生成设计文档 | 30 | 30 |
· Design Review | · 设计复审 (和同事审核设计文档) | 15 | 15 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 0 | 0 |
· Design | · 具体设计 | 15 | 60 |
· Coding | · 具体编码 | 150 | 180 |
· Code Review | · 代码复审 | 30 | 90 |
· Test | · 测试(自我测试,修改代码,提交修改) | 120 | 240 |
Reporting | 报告 | 160 | 230 |
· Test Report | · 测试报告 | 120 | 180 |
· Size Measurement | · 计算工作量 | 10 | 10 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 40 |
合计 | 715 | 1185 |
- 记录自己的学习进度条(每周追加)
| 第N周 | 新增代码行 | 累计代码 | 本周学习耗时 | 累计学习耗时 | 重要成长 |
|-----------------------------------------|-----------------------------------------|------------------|------------------|-----------------------|
|1 | 100 | 100 | 8 | 8 | 把文件各个情况捋清,并完成基本功能|
|2 | 215| 215| 11.5 | 19.5 | 学会C文件的读取,并将扩展功能完善|