https://github.com/huabei-li/personal-project
| PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
| Planning |
计划 |
15 |
20 |
| · Estimate |
· 估计这个任务需要多少时间 |
400 |
720 |
| Development |
开发 |
200 |
300 |
| · Analysis |
· 需求分析 (包括学习新技术) |
150 |
200 |
| · Design Spec |
· 生成设计文档 |
30 |
20 |
| · Design Review |
· 设计复审 |
30 |
30 |
| · Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
20 |
10 |
| · Design |
· 具体设计 |
50 |
60 |
| · Coding |
· 具体编码 |
300 |
400 |
| · Code Review |
· 代码复审 |
30 |
30 |
| · Test |
· 测试(自我测试,修改代码,提交修改) |
30 |
120 |
| Reporting |
报告 |
60 |
90 |
| · Test Repor |
· 测试报告 |
30 |
30 |
| · Size Measurement |
· 计算工作量 |
10 |
10 |
| · Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
30 |
30 |
| | 合计 |1385 |2070
作业要求实现对文本文件中的单词词频做出统计,拿到题的时候先想到了以前做过的对句子单词统计,对文件单词统计的差异在于文件存在多个行。但是也可以想作对文件中的多个行进行统计。在代码中体现为countWord1()将文件的每一行送入countWord2(),countWord2进行单词的判断和数量的统计,同时将单词信息存入unordered_map里,便于topten()函数的字数统计。topten()函数利用了百度的对value值排序的方法,并输出了出现频率前十的单词。countChar_Line()用于统计字符和行数。这是大致的思路。
逻辑结构如图所示

关于接口。如果按照以前的习惯,基本上都是讲所有的功能都写在一起,显得代码很乱。将主要功能都独立成函数,把操作对象相似的函数都放在一个类里,条理和逻辑都比较直观。没有把统计输出的语句集成函数,是受到C++老师的影响(如果函数有输出会带来调试的负担,特别在合作开发时)。
创建了class file,将对文件统计的一些信息,功能都集合在一起,便于理清结构。
部分主要函数代码
countWord1() 对文件读行操作
void countWord1()
{
string File, temp;
fstream file(fname);
while (getline(file, File))
{
File.append(temp);
temp.clear();
for (int i = 0; i < File.length(); i++)
{
if (File[i] == '\n')
File[i] = ' ';
if (ispunct(File[i]))
File[i] = ' ';
}
stringstream ss(File);
countWord2(ss);
}
}
countWord2() 判断单词,统计数量,存入unordered_map
void countWord2(stringstream &ss)
{
string stemp;
while (ss >> stemp)
{
for (int i = 0; i < stemp.length(); i++)
{
if ('A' < stemp[i] && stemp[i] < 'Z')
stemp[i] += 32;
}
if (stemp.length() < 4)
{
continue;
}
if ((stemp[0]>'z' || stemp[0]<'a' || stemp[1]>'z' || stemp[1]<'a' || stemp[2]>'z' || stemp[2]<'a' || stemp[3]>'z' || stemp[3]<'a'))
{
continue;
}
numWords++;
unordered_map<string, int>::iterator it = My.find(stemp);
if (it == My.end())
{
My.insert(unordered_map<string, int>::value_type(stemp, 1));
}
else
My[stemp]++;
}
}
topTen() 按照value排序输出前十单词(啪啪打脸,函数有输出是觉得功能比较统一)
(更新)最近的更新把输出给挪出去了
void topTen()
{
vector<pair<string, int>> VM;
for (auto it = My.begin(); it != My.end(); it++)
{
VM.push_back(make_pair(it->first, it->second));
}
sort(VM.begin(), VM.end(), [](const pair<string, int> &x, const pair<string, int>&y)->int {return x.second > y.second; });
int c = 0;
for (auto it = VM.begin(); c < 10; it++, c++)
{
cout << it->first << ":" << it->second << endl;
}
}
关于注释,习惯上是对于比较难搞混的变量进行解释,对于比较直观的函数等没有做出太多的说明。个人认为过多的注释会使代码看起来太乱,而且这一次的代码量也不需要太多的注释。因为这一次的代码都是给自己看的,所以看懂就好了,如果是合作完成的话,还是尽量把功能都注释清楚比较好。
如图


关于测试数据的设计,除了应尽可能地照顾所有的情况,还要考虑对于大文件的测试时间消耗。从网上找了一部原著资源,跑了一下感觉还是比较快的,得益于数据结构方面的选择还是比较合适的,没有走太多弯路。
利用visual studio 2017 的性能测试工具


相关信息都在图上了
关于单元测试:尝试了一下但是没有实现,对这个还是不太清楚还需要进一步的尝试。如果按照我自己的理解,每完成一个特定的功能是要事先测试一下是否能正确完成,每一部件都能正常工作再组合在一起。
关于异常处理:当程序运行时发生了特殊情况,异常处理能够提供转移程序控制权的方式,从网上看了很多资料,尝(xia)试(xie)了一些类似的代码,写了一个最简单的:当文件读取失败时报出异常(我真机智),当文件打开失败时,throw出一个错误提示。
(更新)最大的一个问题!:关于文件的读取真的是犯了一个贼大的错误。按照要求是需要控制台输入文件。当时望文生义是控制台给出路径……也没有百度具体含义,之前也没接触主函数参数,所以就用的是文件路径打开文件,而且全程都用了这个路径……导致现在要想修改正确要大改……真的是无法原谅的错误,导致在最后测试的时候可能写的程序都不能正常运行。尝试是否能在规定时间内修改正确,但是真的来不及,函数的功能结构都要改掉。
第一次作业如果只是实现功能的话不是很难,花大概两天多的时间查找资料,学习新知识就能写个差不多。但是做起来还是感觉比较匆忙,后续的git,性能分析,测试,单元测试,异常处理之前都没有接触过,要学习的东西很多。这一次作业也就这样七七八八的写成这个样子了,有很多缺陷和不完善的地方,希望能考虑到各种功能和尽可能多的情况。花了很多时间,学到了很多东西,再一次受到打击。很多东西不是浅显易懂的,通过实践能够加深理解,但是也就增加了开始操作的难度。以前对于编码的工作的重点都集中在功能实现上,这一次则还要考虑各个部件的性能,异常处理,测试等等。花的时间不少(每一步都有挺费时间的),但是学习的效果不明显,希望通过积累能有慢慢的改善吧。