软工实践——结对作业2【wordCount进阶需求】
附录:
一、具体分工
- 我负责撰写爬虫爬取信息以及代码整合测试,队友子恒负责写词组词频统计功能的代码。
二、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
• Estimate | • 估计这个任务需要多少时间 | 880 | 1170 |
Development | 开发 | ||
• Analysis | • 需求分析 (包括学习新技术) | 100 | 120 |
• Design Spec | • 生成设计文档 | 20 | 10 |
• Design Review | • 设计复审 | 10 | 10 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 20 | 60 |
• Design | • 具体设计 | 60 | 100 |
• Coding | • 具体编码 | 400 | 510 |
• Code Review | • 代码复审 | 60 | 90 |
• Test | • 测试(自我测试,修改代码,提交修改) | 100 | 180 |
Reporting | 报告 | ||
• Test Repor | • 测试报告 | 30 | 30 |
• Size Measurement | • 计算工作量 | 20 | 15 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 60 | 45 |
合计 | 880 | 1170 |
三、解题思路与具体实现说明。
1、爬虫使用
- 因为之前从来没有接触过爬虫和python代码,所以自己上网搜索了网课。然后看网课一句一句写的代码,用谷歌浏览器的“检查”功能查看要爬取内容在网页中属于什么元素并进行相关爬取。(可能看上去写得"很丑"并且效率不太高)。大概爬取了10多分钟的信息,爬下来979篇论文标题和摘要存入result.txt文件中,下面是我的爬虫代码:
import requests
from urllib.request import urlopen
from bs4 import BeautifulSoup
txt = open(r'C:\Users\Administrator\Desktop\result.txt','w',encoding='utf-8')
#打开文件
i = 0
def getPaper(newsUrl): #获取相关信息的函数
res = requests.get(newsUrl) #打开链接
res.encoding = 'utf-8'
soup = BeautifulSoup(res.text,'html.parser') #把网页内容存进容器
Title = soup.select('#papertitle')[0].text.strip() #找到标题元素爬取
print("Title:",Title,file=txt)
Abstract = soup.select('#abstract')[0].text.strip() #找到摘要元素爬取
print("Abstract:",Abstract,"\n\n",file=txt)
return sUrl = 'http://openaccess.thecvf.com/CVPR2018.py'
res1 = requests.get(sUrl)
res1.encoding = 'utf-8'
soup1 = BeautifulSoup(res1.text,'html.parser')
for titles in soup1.select('.ptitle'): #返回每个超链接
t = 'http://openaccess.thecvf.com/'+ titles.select('a')[0]['href']
print(i,file=txt)
getPaper(t) #循环打开每个子页面并进行爬取
i=i+1
2、代码组织与内部实现设计
- 代码包含一个主要的类testfile以及实现功能的函数,类图如下所示。
- Abstract和Title是分别存放摘要和标题内容的字符串。
- outputByLine函数是在判断词组词频时能够按行返回文本内容并且剔除“Title: "和"Abstract: "。
- phrasecounts分割词组并且计算词组数目与词频。
- sWord结构体用作对词汇进行相关排序的容器。
3、关键算法的实现思路以及代码解释
(1)命令行参数的判断
- 功能流程图如下:
- 功能设计代码以及具体思路注释:
while () //循环判断命令行参数
{
i++;
if (i == argc)
break;
if (argv[i][] == '-') //判断当前参数首字符是否为'-'
{
switch (argv[i][]) //判断当前参数第二个字符
{
case 'i':
{
i++;
input = argv[i];//第二个字符为i时输入下一个参数赋值给input
break;
}
case 'o':
{
i++;
output = argv[i];//第二个字符为o时输入下一个参数赋值给output
break;
}
case 'w':
{
i++;
judgeW = atoi(argv[i]);//第二个字符为w时judgeW为下一个参数的整数值留作输出判断
break;
}
case 'm':
{
i++;
judgeM = atoi(argv[i]);//第二个字符为m时judgeM为下一个参数的整数值留作输出判断
break;
}
case 'n':
{
i++;
judgeN = atoi(argv[i]);//第二个字符为n时judgeN为下一个参数的整数值留作输出判断
break;
}
default:
cout << "输入参数有误" << endl;
break;
}
}
}
- 配合命令行参数判断的输出代码:
if (judgeW == )
{
if (judgeM == ) //非权重词频统计
{
f1 = f1.countline(input, f1);
f1.Abstract = changeDx(f1.Abstract);
f1.Title = changeDx(f1.Title);//大小写转换
f1 = f1.countword(f1, f1.Title, );
f1 = f1.countword(f1, f1.Abstract, );
}
else //非权重词组词频统计
{
f1 = f1.outputByLine(input, f1, , judgeM);
}
}
else
{
if (judgeM == ) //权重词频统计
{
f1 = f1.countline(input, f1);
f1.Abstract = changeDx(f1.Abstract);
f1.Title = changeDx(f1.Title);//大小写转换
f1 = f1.countword(f1, f1.Title, );
f1 = f1.countword(f1, f1.Abstract, );
}
else //权重词组词频统计
{
f1 = f1.outputByLine(input, f1, , judgeM);
}
} if (judgeN == )//如果没有定义n那么按默认输出
outCome1(ww, num, output, f1);
else
{
if (judgeN > f1.getwords())
{
cout << "输入的n值超过了文本的所有单词数,将为您按序输出文本的所有单词" << endl;//对于参数过大的错误判断
outCome2(ww, f1.getwords(), output, f1);
}
else
{
outCome2(ww, judgeN, output, f1);//如果定义了n那么输出前n个
}
}
(2)词组词频统计和权重词频统计的实现
- 词组词频统计算法的设计流程图:
- 具体的代码实现和思路解析
testfile testfile::phrasecounts(string temp, int t, int quan, testfile f1)
{
int word = ;
int i = ;
int j = ;
long int n = ;
int m = ;
string sumwr = "";//初始化一个存放词组的字符串
n = temp.length();
char x[];
for (j = ; j < n; j++)
{
if (temp[j] >= 'A'&&temp[j] <= 'Z')
{
temp[j] += ;
}
}
string phrase;
int flag = , k = ;
int mark = , al = ;//mark用来记录存储的单词数,al用来记录成词组的第二个单词的首字母序号
for (i = ; i < n; i++)
{ if (!((temp[i] >= && temp[i] <= ) || (temp[i] >= && temp[i] <= )))
{
if (mark > )
{
sumwr = sumwr + temp[i];//如果此时已记录一个及以上的单词,将此分隔符也录入词组字符串
}
continue;
}
else
{
for (j = ; j < && i < n; j++)
{ if (!((temp[i] >= && temp[i] <= ) || (temp[i] >= && temp[i] <= )))
{
mark = ;
sumwr = "";//检测到非法单词,重新初始化mark和词组字符串
break;
}
else
{
if (j == && mark == )
{
al = i;
}
x[j] = temp[i++];//temp中存入四个非空格字符
}
}
if (j == )
{
for (m = ; m < ; m++)
{
if (x[m] < || x[m]>)
{
flag = ;
mark = ;
sumwr = "";
break;//判断这四个字符是否都是字母,检测到非法单词,重新初始化mark和词组字符串
}
}
if (flag == )//判断为一个单词
{
char *w = new char[];//存放单词
for (m = ; m < ; m++)
{
w[k++] = x[m];//temp中字符存入w
}
while (((temp[i] >= && temp[i] <= ) || (temp[i] >= && temp[i] <= )) && i < n)//继续存入单词剩余字符
{
w[k++] = temp[i++];
}
w[k] = '\0';
sumwr = sumwr + w;//将单词存入词组字符串数组
mark++;
delete[]w;
k = ;
if (mark == t)
{
loadword(sumwr, quan);//如果此时单词存入达到所需数量,将此词组字符串存入map函数,并初始化mark和字符串
word++;
mark = ;
i = al;//让i等于存入字符串的第二个单词的第一个字母序号,重新开始查询词组
sumwr = "";
}
i--;
}
else
{
flag = ;
j = ;
mark = ;
sumwr = "";
}
}
} }
i = ;
f1.words += word;
return f1;
}
四、性能分析以及改进思路
- 输入的命令行参数为:-i C:\Users\Administrator\Desktop\result.txt -m 2 -n 20 -w 1 -o C:\Users\Administrator\Desktop\output.txt 即对爬取的文件进行词组分割,2个单词一组而后执行权重词频统计并且输出频率最高的前20个词组。
- 性能探查器返回结果
- 因为本次测试执行的是词组分割的词频统计,所以占比最高的函数就是词组分割函数phrasecount。其次本次程序执行时间在15秒到16秒左右,所以还有优化空间。loadword是把词组存入map,这是c++自带的一个统计词频并且按字典排序的容器,如果有能力的话希望自己能用哈希表写一个类似的排序也许能够提高运行效率。
五、单元测试
- 以下对字符数统计,行数统计,单词数统计以及词组分割和词组词频统计四个函数进行单元测试。
#include "stdafx.h"
#include "CppUnitTest.h"
#include "C:\Users\Administrator\Desktop\软工实践\结对作业2\单元测试\WordCount2\WordCount2\WordCount2\WordCount2.h"
#include <iostream>
using namespace Microsoft::VisualStudio::CppUnitTestFramework; namespace WordCountTest1
{
TEST_CLASS(UnitTest1)
{
public: TEST_METHOD(phraseCount)
{
testfile f1;
f1=f1.outputByLine("C:\\Users\\Administrator\\Desktop\\result.txt", f1, , );//按行输出后进行词组词频统计
}
TEST_METHOD(wordCount)
{
testfile f1;
f1 = f1.countline("C:\\Users\\Administrator\\Desktop\\result.txt", f1);
f1 = f1.countword(f1, f1.Abstract, );
f1 = f1.countword(f1, f1.Title, );
}
TEST_METHOD(countCharacters)
{
testfile f1;
string a;
f1 = f1.countcha("C:\\Users\\Administrator\\Desktop\\result.txt", f1);
Assert::AreEqual(f1.getcharacters(), (int));
}
TEST_METHOD(countLine)
{
testfile f1;
f1 = f1.countline("C:\\Users\\Administrator\\Desktop\\result.txt", f1);
Assert::AreEqual(f1.getlines(), (int));
}
};
}
- 单元测试通过
- 观察单元测试图可以看到,在对一百万字符数的文本文档进行统计时,总执行时间要20秒,其中词组分割花费11秒最多,再者就是单词分割,需要6秒。还有很大的优化空间啊。
六、Github签入记录
- 共签入了三次。第一次是自己做的那块功能做完后签入。而后队友做的功能完善后,整理合并到代码里再次签入。第三次签入时进行完单元测试并加入爬虫结果。
七、遇到的困难
- 因为我和队友都对于爬虫不熟悉,所以我们一开始决定使用c++来写爬虫,但是在写的过程中遇到较多问题没法解决,决定改用python写爬虫,所以我就去看网课写了一个爬虫。
- 在决定分工写功能模块的时候,队友是在他自己之前个人项目的代码基础上添加的词组词频统计功能,而他的代码和我的代码在函数传递的参数上有很多不同,所以在代码合并的时候出现了很多bug,为此我们讨论了挺久终于把bug解决了。
- 在对问题做需求分析的时候,我们对词组词频统计的要求理解错了,队友在某天晚上肝到了3点(超级拼,点赞,但要注意身体)写了一个各种判断的词组词频统计函数,第二天测试时发现和样例有较大出入。(这时内心是绝望的)所以第二天在重新理解需求之后再次写了一个词组词频统计函数。
八、对于队友的评价
- 我的队友子恒是我的舍友,我觉得他的脑筋很灵活,并且坚持不懈从不抱怨。其实分工上感觉我做得多一些,但是他做的那部分比较难。说实话如果是我写了很久的一个函数,发现需求理解错误要重写,我可能会崩溃哈。所以给舍友及队友子恒赞一个!虽然我们的工作效率都不高,都是代码小渣渣,不过遇到问题时能交换思维也可以成功解决的。
九、学习进度条
第N周 | 新增代码行 | 累计代码行 | 本周学习(时) | 重要成长 |
---|---|---|---|---|
2 | 255 | 255 | 11 | 熟悉了c++的一些函数使用以及c++输入输出流 |
3 | 105 | 350 | 13 | 初步接触了代码性能分析以及一些调试方法。学习了RP制作原型的方法。 |
4 | 0 | 350 | 6 | 本周主要是看邹欣老师的《构建之法》,第一章到第三章。以及组队讨论项目。 |
5 | 60 | 410 | 8 | 看网课学习写爬虫。 |
6 | 176 | 586 | 12 | 熟悉了命令行参数的传递。初步了解代码单元测试。 |
软工实践——结对作业2【wordCount进阶需求】的更多相关文章
- [BUAA软工]第一次结对作业
[BUAA软工]结对作业 本次作业所属课程: 2019BUAA软件工程 本次作业要求: 结对项目 我在本课程的目标: 熟悉结对合作,为团队合作打下基础 本次作业的帮助:理解一个c++ 项目的开发历程 ...
- 结对作业二——WordCount进阶版
软工作业三 要求地址 作业要求地址 结对码云项目地址 结对伙伴:秦玉 博客地址 PSP表格 PSP2.1 个人开发流程 预估耗费时间(分钟) 实际耗费时间(分钟) Planning 计划 10 7 · ...
- 软工实践——团队作业需求规格说明书——原型UI设计
登录界面 还包含忘记密码和注册的功能 注册界面 注册成功后会有弹窗提示,且一个手机号只能注册一次. 忘记密码界面 通过手机收到的验证码更改密码. 项目界面 登陆之后的页面就是这个项目界面.在拥有的界面 ...
- 结对第2次作业——WordCount进阶需求
作业题目链接 队友链接 Fork的同名仓库的Github项目地址 具体分工 玮哥负责命令参数判断.单词权重统计,我只负责词组词频统计(emmmm). PSP表格 预估耗时(分钟) 实际耗时(分钟) P ...
- 软工实践第五次作业-WordCount进阶需求
软工实践作业(五) GitHub 作业链接 结对博客 031602240 具体分工 PSP表格 代码规范 解题思路与设计说明 爬虫使用 代码组织与内部实现设计(类图) 算法关键 实现方法 流程图 附加 ...
- 【2017集美大学1412软工实践_助教博客】团队作业10——项目复审与事后分析(Beta版本)
写在前面的话 转眼轰轰烈烈本学期的软工实践就结束了,这个过程中想必在熬夜敲代码,激烈讨论中留下诸多回忆的同时,也收获了不少.恭喜所有团队完成了本阶段冲刺,此外,由于大家的贡献分给的都很平均,将个人贡献 ...
- 《软工实践》第零次作业 - 一些QA
<软工实践>第零次作业 - 一些QA Q&A (1)回想一下你初入大学时对计算机专业的畅想 当初你是如何做出选择计算机专业的决定的? 你认为过去两年中接触到的课程是否符合你对计算机 ...
- 福州大学2020年春软工实践W班第二次作业
作业描述 这个作业属于哪个课程 福州大学2020年春软工实践W班 这个作业要求在哪里 寒假作业(2/2) 这个作业的目标 开发一个疫情统计程序 作业正文 福州大学2020年春软工实践W班第二次作业 其 ...
- 福州大学2020年春软工实践W班第一次作业
作业描述 这个作业属于哪个课程 福州大学2020年春软工实践W班 这个作业要求在哪里 寒假作业(1/2) 这个作业的目标 建立博客.回顾,我的初心.当下和未来.学习路线 作业正文 福州大学2020年春 ...
随机推荐
- python(3)之字符串
字符串常用操作如下: name="huang yuqing"print(name.count("h"))#计算包含字符的个数print(name.capital ...
- angular4,angular6中解决内层盒子到底外层盒子滚动
//用来处理 里盒子滚完外盒子滚的问题 scrollUnique(who){ document.getElementsByClassName(who)[0].addEventListener('mou ...
- 一个非常适合IT团队的在线API文档、技术文档工具 (ShowDoc)
在逸橙呆了不到两年,开发时后端都有开发接口API,来到数库,好多后端开发和前端沟通是还是发doc文档,很不方便,我向cto反应,自己找到这个,老乡田雷(php,隔壁村的)也用过,可能某些原因选择其他的 ...
- nginx:负载均衡(三)分流策略
[1]轮询策略.轮询策略是最简单的策略,无脑配置,不考虑服务器的访问的能力.每个请求按照时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除 upstream www.daysn. ...
- Java Swing 简单介绍
Swing 是一个为Java设计的GUI工具包. Swing是JAVA基础类的一部分. Swing包括了图形用户界面(GUI)器件如:文本框,按钮,分隔窗格和表. Swing提供许多比AWT更好的屏幕 ...
- 直接插入排序(Straight Insertion Sort)
body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...
- css动画库
转载自:http://www.cnblogs.com/starof/p/4968769.html 本文作者starof,因知识本身在变化,作者也在不断学习成长,文章内容也不定时更新,为避免误导读者,方 ...
- ajax之同步异步详解
同步:一堆任务,按顺序去执行,只能一件件的来,如一个厨师做菜 异步:一堆任务,可以同时进行,如多个厨师做菜 ...
- DevExpress v18.1新版亮点——XAF篇(一)
用户界面套包DevExpress v18.1日前正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExpress eXpressApp Framework(XAF) v18.1 ...
- mybatis 插入空值时报错 TypeException
报错内容:nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ...