Fzu软工第二次作业-词频分析
(0)前言:
(1)PSP表格:
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 40 |
• Estimate | • 估计这个任务需要多少时间 | 30 | 40 |
Development | 开发 | 1070 | 1300 |
• Analysis | • 需求分析 (包括学习新技术) | 150 | 200 |
• Design Spec | • 生成设计文档 | 50 | 60 |
• Design Review | • 设计复审 | 30 | 20 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 40 | 20 |
• Design | • 具体设计 | 200 | 50 |
• Coding | • 具体编码 | 360 | 330 |
• Code Review | • 代码复审 | 40 | 360 |
• Test | • 测试(自我测试,修改代码,提交修改) | 200 | 260 |
Reporting | 报告 | 110 | 120 |
• Test Repor | • 测试报告 | 50 | 60 |
• Size Measurement | • 计算工作量 | 30 | 25 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 30 | 35 |
合计 | 1210 | 1460 |
(2)解题思路描述:
- 刚拿到题目后,我发现本题只是要求我们实现一个控制台程序,通过命令行参数传入一个文本后,将文本进行解析,分析出文本里的字符数,单词数,有效行数等内容。总体而已,这个程序的基本功能并不是很难。
-由于我对于java的学习比较浅显,现在已经忘的差不多了,所以我用了c++,思路有很多。编程其实并不难,同一个问题有多种实现方法,并且大问题很容易可以拆成小问题,分块解决。 - 例如这题我想了两个思路,一个是先把文件预处理,可以利用fread把文件读取成字符串,之后按照特定的分割符可以利用类似split函数,判断合法的单词,统计字符数。另一个思路是利用ifstream文件流读出txt文件的内容,之后用getline按行读出文件,并且vector存储单词,并且用map按字典序存储单词。
不过存在两个问题:
- 1.用map储存有一个问题,就是map只能按特定的key值存储单词,并不能在此基础上按单词出现的频率排序,因此我用multimap多重映射对单词再次排序,如此一来就可以按单词频率按字典序排序。
- 2.我以前没有用过通过命令行参数传入一个文件名,因此我学习了一下ifstream怎么读取输出文件。
(3)设计实现过程:
- 本项目我采用类进行接口封装,关于类的说明与接口的函数在stdafx.h文件里,关于接口的详细代码内容在stdafx.cpp文件里。
-对于本作业,主要我设计了两个类,一个类是Word类用于进行词频分析以及存储词频分析的结果.另一个类File是用于进行文件的异常测试。
Word类包含了5个函数:
Word();//用于初始化
int Countcharacters(char *argv);//用于统计字符数
int Countlines(char *argv);//用于统计空白行
int Countwords(char *argv);//用于统计单词数
vector<pair<string,int>> Counttop10(char *argv);//统计词频前十的单词
File类包含了2个函数:
File();//用于初始化
int FileTest(char *argv[]);//用于文件异常测试
模块分析:
- Countcharacters函数是用于统计字符数的,主要是根据题意,遍历一次文件里的字符串,判断字符是否是在0到127,属于Ascill码的范围。
- Countlines函数是用于统计空白行,在分析这个功能的时候,需要先理解什么是空白字符串,主要包括tab,空格跟回车三种,只要按行读取,判断该行内是否存在除这三者以外的字符,就可以判断是否是空白行。
- Countwords函数用于统计单词数,我主要是先通过大小写转化,把合法单词所可能用的字符大小写转化,之后用ans作为标记,判断是否存在开头为4个连续的字母的单词,若存在合法单词,则用map进行存储。
- Counttop10用于统计词频前十的单词,属于这次词频分析作业里的核心函数,同样是找出合法单词用map按字典序存储,多重映射的multimap,将key设为单词的词频,按词频进行字典序排序,由于map要求key值唯一,而multimap可以多重映射,因此我使用multimap进行排序,最后用vector和pair存储词频前十的单词。核心代码见(5)
(4)性能分析及改进:
测试文件input.txt内容:
vasdvs
bsbsdb.vasdvs
;casv[vdav/vv
vas.vsv+v
casvsa2000
casvsa1998
as*casvsa2001
123acasv;;;;;
12sav
vasdvs
vdv++
12sav;;fas
b
测试文件结果:
characters: 130
words: 9
lines: 13
<vasdvs>: 3
<bsbsdb>: 1
<casv>: 1
<casvsa1998>: 1
<casvsa2000>: 1
<casvsa2001>: 1
<vdav>: 1
我将这个文件循环测试了10000次,性能分析结果如图:
从图可以看出Countwords函数占了接近35%的时间,Counttop10占了快20%的时间,总耗时28s,由于我一开始是在执行Countwords过程中,顺便用map存储合法单词,由于题目要求是要三个独立的接口,因此我在调用Counttop10函数时是先执行了一次Countwords函数。因此我把两个进行拆分,做出改进。
改进后Countwords函数只用于统计单词个数,Counttop10则是先自行遍历一次文件,查找合法单词后,进行后续操作,改进后性能分析结果如图:
改进结果,时间减少了3s,Countwords占用时间大幅度减少。
(5)项目关键代码:
Counttop10函数:
vector<pair<string, int>> Word::Counttop10(char *argv)
{
//利用多重映射的multimap,将单词按词频字典序排序,之后用vector存储前十的单词
mapword.clear(); //先对原本的map初始化
map<string, int>::iterator iter; //迭代器
multimap<int, string> mapint;
multimap<int, string>::iterator iter2;
string name, word;
long ans, num, i, j, wordpos;
vector<pair<string, int>> top10;
ifstream Fileread; //读出文件
Fileread.open(argv, std::ios::in);
if (Fileread.fail()) //异常检测
{
printf("file isn't exist\n");
return top10;
}
while (!Fileread.eof())
{
getline(Fileread, name); //按行读取文件
ans = 0; wordpos = 0;
num = name.size();
for (i = 0; i<num; i++)
{
if (65 <= name[i] && name[i] <= 90)name[i] += 32;//大小写转化
//判断是否为合法单词
if (97 <= name[i] && name[i] <= 122)
{
ans++;
continue;
}
if ('0' <= name[i] && name[i] <= '9')
{
if (ans >= 4)
{
continue;
}
else
{
for (j = i; j<num; j++)
{
if ('0' <= name[j] && name[j] <= '9')
continue;
else if (('a' <= name[j] && name[j] <= 'z') || ('A' <= name[j] && name[j] <= 'Z'))
continue;
else
{
//寻找下一个合法单词的开头
while (j<num)
{
if (('a' <= name[j + 1] && name[j + 1] <= 'z') || ('A' <= name[j + 1] && name[j + 1] <= 'Z'))
{
wordpos = j + 1;
break;
}
else
j++;
} //寻找下一个单词的开头
i = j;
break;
}
} //寻找下一个分隔符
if (j == num)
{
break;
} //寻找不到下一个分隔符
ans = 0;
}
}
else
{
if (ans >= 4)
{
//添加单词
word = name.substr(wordpos, i - wordpos);
iter = mapword.find(string(word));
if (iter != mapword.end())
iter->second += 1;
else
mapword.insert(pair<string, int>(word, 1));
// cout<<"word:"<<word<<endl;
}//获取单词
while (i<num)
{
if (('a' <= name[i + 1] && name[i + 1] <= 'z') || ('A' <= name[i + 1] && name[i + 1] <= 'Z'))
{
wordpos = i + 1;
break;
}
else
i++;
} //寻找下一个合法单词的开头
ans = 0;
}
}
//防止该行以合法单词结尾
if (ans >= 4)
{
word = name.substr(wordpos, i - wordpos);
iter = mapword.find(string(word));
if (iter != mapword.end())
iter->second += 1;
else
{
mapword.insert(pair<string, int>(word, 1));
}
}
}
num = 0;
iter = mapword.begin();
for (; iter != mapword.end(); iter++)
{
mapint.insert(pair<int, string>(-iter->second, iter->first));
}
for (iter2 = mapint.begin(); iter2 != mapint.end(); iter2++)
{
num++;
top10.push_back(make_pair(iter2->second.c_str(), -(iter2->first)));
if (num == 10)
break;
}
Fileread.close();
return top10; //返回一个vector
}
(6)单元测试:
本次作业共设置了10个单元测试点,分别用于测试:
- 测试空白文件
- 测验没有命令行参数
- 测试文件不存在
- 测试单词数字开头的情况
- 测试大小写单词是否能识别
- 测试空白行是否识别
- 测试Countlines函数
- 测试Countwords函数
- 测试Countcharacters函数
- 测试Counttop10函数
单元测试结果:
代码测试覆盖率:
其中stdafx.cpp覆盖率较低的原因是写了一些文件异常处理的代码,如下图:
(7)异常处理:
- 针对异常处理我主要设置了三种情况,一种是命令行无参数,一种是命令行有多个参数,一种是命令行参数地址错误
- FileTest(char *argv[]);//用于文件异常测试
int File::FileTest(char *argv[])
{
if (argv[1] == NULL)
{
printf("no file\n");
return 0;
}
if (argv[2] != NULL)
{
printf("too much\n");
return 0;
}
fstream Fileread;
Fileread.open(argv[1], std::ios::in);
if (Fileread.fail())
{
printf("file isn't exist\n");
return 0;
}
Fileread.close();
return 1;
}
(8)项目小节及个人感想:
- 本实验我是用c++写的,可能由于参加过acm,学习过一些算法的知识,实现代码的基本功能对我并不是很困难,主要难点在于我以前没用使用过vs,对于vs的功能基本上是属于一知半解的,因此我大部分的时候是学习vs的功能。原本接口的封装我是想采用dll封装,后面因为时间原因,临时换回了class封装,感觉这次在代码改进上做的不够,原本想文件预处理,Word再预处理后直接存储ifstream 的指针,这样再后面调用其他函数时,就可以节省一些开销,不过尝试没用成功,准备等之后有时间再查查fstream文件流的详细原理,看看这个方法是否可行再进行尝试。
Fzu软工第二次作业-词频分析的更多相关文章
- SudokuGame 记软工第二次作业
整体概况 1.描述编写整体程序正确过程(含关键代码) 2.整体心路历程及新知分析 3.效能分析.构建之法及整体耗时时间表 4.一些心得体会 GitHub 链接如下: 1.[基础作业BIN文件(最新版) ...
- 2017软工第二次作业 - 本周PSP(补交)
每周例行报告 1.本周PSP 2. 本周进度条 3.累计进度图 4. 本周PSP饼状图
- 软工实践——结对作业2【wordCount进阶需求】
附录: 队友的博客链接 本次作业的博客链接 同名仓库项目地址 一.具体分工 我负责撰写爬虫爬取信息以及代码整合测试,队友子恒负责写词组词频统计功能的代码. 二.PSP表格 PSP2.1 Persona ...
- 软工个人阅读作业2 —— 构建之法与CI/CD
项目 内容 这个作业属于哪个课程 2021春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 个人阅读作业#2 我在这个课程的目标是 阅读思考教材,调研软工工具 这个作业在哪个具体方面帮助我实 ...
- 2020BUAA软工结伴项目作业
2020BUAA软工结伴项目作业 17373010 杜博玮 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 结伴项目作业 我在这个课程的目标是 学 ...
- 2020BUAA软工个人项目作业
2020BUAA软工个人项目作业 17373010 杜博玮 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 个人项目作业 我在这个课程的目标是 学 ...
- FZU软工第五次作业-词组频率分析
目录 00.前言: 01.分工: 02.PSP表格: 03.解题思路描述与设计实现说明: 解题思路简述: 关键代码 04.附加题设计与展示: 设计的创意独到之处 实现思路 实现成果展示 05.关键代码 ...
- [BUAA软工]第二次博客作业---结对编程
[BUAA软工]结对作业 项目 内容 这个作业属于哪个课程 北航软工 这个作业的要求在哪里 2019年软件工程基础-结对项目作业 我在这个课程的目标是 学习如何以团队的形式开发软件,提升个人软件开发能 ...
- FZU软工第四次作业-团队介绍
目录 团队展示----旅法师 团队成员 队名----旅法师 拟作的团队项目描述 队员风采 团队首次合照 团队的特色描述 团队展示----旅法师 本次作业链接 团队成员 031602305 陈玮 031 ...
随机推荐
- Flutter学习笔记(四)--Flutter几个小知识点
Flutter的Widget采用的是现代化的React风格,该风格的设计灵感来源于React这么语言.最核心的理念是你可以使用Widget设计界面.Widget通过当前的state和注册信息来描述vi ...
- windows下的mongodb安装(真垃圾)
一.下载 3.6下载安装会卡死.只能下3.4的.http://downloads.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-v3.4-la ...
- Image():强制让图片缓存起来
Image 对象 Image 对象代表嵌入的图像. <img> 标签每出现一次,一个 Image 对象就会被创建. 创建一个Image对象:var a=new Image(); 定义 ...
- 微信公众号菜单添加小程序,miniprogram,pagepath参数详解,php开发公众号
随着微信小程序功能的开发, 已经可以跟公众号打通了, 主要有两种方式: 1) 在公众号文章中插入小程序 2) 在公众号菜单中添加小程序 第一种方式, 子恒老师在前面的课程已经详细介绍过, 今天来讲第二 ...
- Yii 语言设置 中文提示信息
1. 在main.php配置文件中加入 'language'=>'zh_cn', 注: 在URL中追加参数lang=zh_cn即可实现中文 2. 在Controller方法中添加 publi ...
- response.sendRedirect跳转 jsp:forward跳转
response.sendRedirect跳转 <% response.sendRedirect("online.jsp"); %> jsp:forward跳转 < ...
- Silverlight自定义控件系列 – TreeView (1)
原文路径:http://blog.csdn.net/wlanye/article/details/7265457 很多人都对MS自带的控件不太满意(虽然MS走的是简约风格),都会试图去修改或创建让 ...
- English trip -- VC(情景课) 6 A Time
Words eleven 十一 twelve 十二 thirteen 十三 fourteen fifteen sixteen seventeen eighteen nineteen twenty ...
- 3-15 《元编程》第6章 3-16 hook method
Code That Writes Code 6.1 Coding your way to the weekend 6.2 Kernel#eval, Binding#eval Binding: Obje ...
- MFC中format函数用法
本文转载于:http://blog.csdn.net/sunxc123/article/details/7742982 在MFC程序中,使用CString来处理字符串是一个很不错的选择.CString ...