福大软工1816 · 第二次作业 - 个人项目
一、Github项目地址
Github项目地址
二、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | |
· Estimate | · 估计这个任务需要多少时间 | ||
Development | 开发 | 670 | 1120 |
· Analysis | · 需求分析 (包括学习新技术) | 120 | 300 |
· Design Spec | · 生成设计文档 | 15 | |
· Design Review | · 设计复审 | ||
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | |
· Design | · 具体设计 | 40 | |
· Coding | · 具体编码 | 360 | |
· Code Review | · 代码复审 | 50 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | ||
Reporting | 报告 | 100 | |
· Test Repor | · 测试报告 | ||
· Size Measurement | · 计算工作量 | ||
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 80 |
| | 合计 |790 |1260|
三、解题思路描述
解题思路描述。即刚开始拿到题目后,如何思考,如何找资料的过程。
1、首先,题目要求在程序中对指定文件进行读写操作,并且输入文件名以命令行参数传入。之前有稍微接触过文件读写和命令行传参的相关内容,因此对这部分的要求并未太过纠结。
2、题目的具体要求是统计文件的字符数、有效行数、合法单词数,并字典序输出词频最高的10个合法单词。
- 统计文件的字符数。可以从文件中依次读取字符,通过判断读取到的字符是否为ASCII码进行字符统计。
- 统计文件的有效行数。题目要求“任何包含非空白字符的行,都需要统计。”我的理解是如果一行中只包含空格或制表符,则将其视为空白行,不予统计。可以用getline()函数从文件中逐行读取,去除行中的空格和制表符,如果处理后的字符串的长度仍大于0,则将其视为有效行。思路参考博客1。
- 统计文件中的合法单词数,并字典序输出词频最高的10个合法单词。考虑这个功能的实现花费了我最多的时间和精力。题目对单词的形式提出了要求,即“单词:至少以4个英文字母开头,跟上字母数字符号,单词以分隔符分割,不区分大小写。”另外,题目中提到了单词的分隔符是非字母数字符号,因此就不能简单的根据空格提取单词,提取单词的过程中还要进行对单词格式的检查。所以,我用逻辑判断截取合法单词,用map进行词频统计,最后借助vector输出词频最高的10个合法单词。思路和实现参考博客2。
四、设计实现过程
设计实现过程。设计包括代码如何组织,比如会有几个类,几个函数,他们之间关系如何,关键函数是否需要画出流程图?单元测试是怎么设计的?
1、代码组织
我把程序的主要功能:统计字符数、统计有效行、统计合法单词数和按字典序输出词频最高的10个合法单词封装成了一个Statistics类,没有将文件的操作单独封装成类,在主函数中进行文件的打开和关闭,将文件参数传给类中的统计功能函数,实现统计功能。关系如下:
2、关键函数流程图
int words(ifstream& in)统计单词数及词频流程图:
补充:在i=str.length()-1时,情况1:str[i]为字母,此时若flag>=3,截取合法单词;情况2:str[i]为数字,此时若flag>=4,截取合法单词;情况三:str[i]为非数字字母字符,无特殊处理。
补充2:在进行截取前,如果所选定截取部分的前一个字符为数字,判断为不合法单词,放弃截取。
3、单元测试
我在这一步折腾了很久,先是找资料学习如何进行单元测试,之后在实践中也遇到了很多的问题,特别是没有把测试用的文档放在正确的地方导致测试结果老是失败。
为了更方便地进行单元测试,我对原先程序的封装进行了改动,实施了单元测试之后切实感受到了它的好处,利用单元测试可以很好的检测程序中的功能,我在进行单元测试的过程中就找到了我程序中的几个bug,如果将来要进行大的项目的建设,单元测试带来的方便应该会更加显著。
我设计的单元测试有:回车字符的统计、字符数的统计、有效行数的统计、单词数的统计、合法单词的提取、是否转换为小写字母、词频统计是否正确、单词是否按字典序排列、空文档的统计、仅含空格、制表符、回车的文档的统计。
单元测试部分代码:
namespace UnitTest4//测试单词数的计算
{
TEST_CLASS(UnitTest1)
{
public:
TEST_METHOD(TestMethod1)
{
ifstream in;
in.open("test4.txt", ios::in);
Statistics s;
Assert::IsTrue(s.words(in) == 3);
}
};
}
单元测试结果如下:
单元测试得到的测试覆盖率截图:
主函数里未被覆盖部分为错误处理代码。
五、性能分析和改进
记录在改进程序性能上所花费的时间,描述你改进的思路,并展示一张性能分析图(由VS2017的性能分析工具自动生成),并展示你程序中消耗最大的函数。
选择33.6M的txt文档进行性能分析。
性能分析图:
消耗最大的函数:
消耗最大的函数是Statistics类里统计单词数及词频的函数words(),其中,消耗主要在对map的操作以及文件的读取上。
六、代码说明
展示出项目关键代码,并解释思路与注释说明。
1、统计行数
去除一行中的空格和制表符,如果该行长度仍大于0,说明其为有效行数。
主要代码:
while (getline(in, str))
{
str.erase(std::remove(str.begin(), str.end(), ' '), str.end());//删除一行中的空格
str.erase(std::remove(str.begin(), str.end(), '\t'), str.end());//删除一行中的制表符
if (str.length() > 0) //如果删除制表符和空格之后的一行数据还有其他字符就算有效行
{
line++;
}
}
2、按字典序输出词频最高的10个单词
借助vector输出:将储存于map中的各单词的词频导入vector,接着对vector从大到小排序,最后将vector中排在前十的数字依次与map中记录的词频比对,输出最先匹配到的单词和词频,置输出的单词的词频为0。
map<string, int>::iterator it;
for (it = word.begin(); it != word.end(); it++)
{
int t = (*it).second;
a.push_back(t);
}
sort(a.begin(), a.end(), cmp);
if (wnum == 0)
{
out << "该文档不存在合法单词!" << endl;
}
else
{
for (int i = 0; i < wnum && i < 10; i++)
{
int t = a[i];
for (it = word.begin(); it != word.end(); it++)
{
if ((*it).second == t)
{
out << "<" << (*it).first << "> :" << t << endl;
(*it).second = 0;
break;
}
}
}
}
3、错误处理部分
处理命令行输入参数错误
if (argc != 2)//检测输入的命令行参数是否正确
{
cout << "输入参数错误!" << endl;
exit(1);
}
处理输入输出文件打开失败
infile.open(argv[1], ios::in);
if (infile.fail())
{
cout << "输入文件打开失败!" << endl;
exit(1);
}
outfile.open("result.txt", ios::out);
if (outfile.fail())
{
cout << "输出文件打开失败!" << endl;
exit(1);
}
七、心路历程与收获
结合在构建之法中学习到的相关内容与个人项目的实践经历,撰写解决项目的心路历程与收获。
这次的作业花费了我很多的时间和精力,我的能力比我想象中的还要不足,作业中列出了一项项具体的要求,所以我在实践中就按照这一项项要求去思考、搜索、学习,在搜索过程中我找到了很多比我原先想的要方便得多的解决方法,见识了很多新知识和新技术,可以说,我在这次个人项目里做的最多的就是学习,学习新知识,比如软工的流程和规范、字符串处理、STL的应用,学习新技术,比如vs的单元测试、性能分析等等,这些新知识和新技术算是我这次最大的收获了吧。另外,写博客一直是很让我头疼的一件事,我在写博客上也花费了相当多的时间和精力,怎么在博客中清楚地表达自己的想法和经历,展现自己的成果和收获是一个很重要的能力,我在这方面有很大的欠缺,有待加强,希望以后写博客能成为一项我喜欢的事。
参考资料:
博客1:https://blog.csdn.net/haomingzidoumeilea/article/details/8977012
博客2:https://blog.csdn.net/hisfox/article/details/80013414#t3