第一次个人编程作业
Part 1 : Github项目地址
由于我的vs一直没办法直接把项目上传到github上,一直推送失败。所以我只能在github的对应仓库上“create new file",直接把代码贴上去,望谅解。通过设置新的分支后已经可以成功推送!耶!
Part 2 : PSP(Personal Software Process)表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
· Estimate | · 估计这个任务需要多少时间 | 1800 | 1800 |
Development | 开发 | 1800 | 1700 |
· Analysis | · 需求分析 (包括学习新技术) | 120 | 180 |
· Design Spec | · 生成设计文档 | 60 | 30 |
· Design Review | · 设计复审 | 20 | 20 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 30 |
· Design | · 具体设计 | 120 | 180 |
· Coding | · 具体编码 | 600 | 960 |
· Code Review | · 代码复审 | 300 | 120 |
· Test | · 测试(自我测试,修改代码,提交修改) | 120 | 180 |
Reporting | 报告 | 90 | 120 |
· Test Report | · 测试报告 | 120 | 60 |
· Size Measurement | · 计算工作量 | 20 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 40 |
· 合计 | 1830 | 1850 |
Part 3 : 解题思路描述
(1)拿到题目后如何思考?
在看到助教姐姐发布的第一次编程作业后,我的内心是崩溃的。由于在给出的三种语言要求中,
java没接触过,python选修课学过但学得很浅,所以我就选择了用c++来解题。后来发现用c++简直太难了啊啊啊啊!停止土拨鼠尖叫,回到题目,题目要求将小王打乱的地址簿规范化处理。对我来说,难点在于:一是地址中的“省”、“市”等关键字有可能残缺,这就说明没办法简单的通过匹配该关键字来提取。只能通过暴力打表或者引入地图API来匹配处理;二是没处理过文件的输入输出,需要进一步了解这里面有没有什么陷阱(坑)以及如何规范输入输出;三是好多处理问题上的细节,类处理函数处理之类的。总之就是一个字,难。但生活还是得继续下去,冲!
(2)如何查找资料?
主要有四种方式:翻阅以前的c++教材和c++ primary,熟悉一下可能会用到的语法;利用搜索引擎查找地址模糊匹配等与题目相关类似的博客资料;询问身边的大佬们,向他们请教思路;围观软工群里“神仙打架”,我还没想好怎么做他们已经写好评测工具等着了QUQ。
Part 4 : 设计实现过程
(1)代码组织方式
我定义了一个person类,里面包含成员变量total,name,telnum,province,city,county,street,detailaddr,函数则有stringtowstring转换函数、wstringtostring转换函数、省提取函数、市提取函数以及以下几级地址的提取函数,通过提取函数将提取出来的规范地址赋值给类中对应的成员变量,转换函数则用来实现string和wstring的相互转换。
全局变量与函数如下图:
Person类成员变量如下图:
以下是关系函数的流程图:
(2)算法的关键
总的来说:
我的算法的关键主要是地址的提取函数和字符转换函数。因为不会调用地图API(别问,问就是菜!),所以只能采用暴力的本方法来查找匹配。我建立了地址数组,将普通地址和特殊地址分开,比如直辖市和自治区单独建组,不与普通省份一起,方便匹配并且提取规范地址,赋值比较方便,通过返回已提取地址的字数来简化地址,以便下一步匹配提取。但这种方法非常暴力,效率比较低,还需要进一步的完善改进。;通过stringtowstring和wstringtostring的转换函数来实现字符的转换,方便对字符串的处理和输出。
地址提取函数:
一是省、直辖市、自治区的地址提取函数。因为这种情况下的参数相对较少,因此我就建立了三个全局变量字符数组来存省、直辖市、自治区的地址名称,然后通过函数进行对比匹配。由于存在直辖市和自治区这两种比较复杂的情况,因此我将其分开进行判断,先进行直辖市的判断:
//判断直辖市
for (int i = 0; i < 4; i++) {
if (t == direct_pro[i]) {
addr[p].province = t; addr[p].city = t; addr[p].city += L"市";
if (obj_[2] == L'市') { return 3; }
else return 2;
break;
}
}
自治区的判断:
//判断自治区
if (z == autop[2]) { addr[p].province = L"西藏自治区"; return 5; }
if (z == autop[0]) { addr[p].province = L"内蒙古自治区"; return 6; }
if (z == autop[1]) { addr[p].province = L"宁夏回族自治区"; return 7; }
else if (z == autop[3]) { addr[p].province = L"广西壮族自治区"; return 7; }
if (z == autop[4]) { addr[p].province = L"新疆维吾尔自治区"; return 8; }
普通省份的判断,注意需要把黑龙江省单独提出来判断:
//判断普通省份
for (int j = 0; j < 22; j++) {
if (t == provincebook[j]) {
t += L"省";
if (obj_[2] == L'省') { addr[p].province = t; return 3; break; }
else { addr[p].province = t; return 2; break; }
}
}
二是对市、区/县/县级市、街道/镇/乡、详细地址的提取。到这里我就GG了。不会调地图api,而如果采用上述方法,需要存的参数太过于庞大,因此只能先不考虑“市”、“县”等关键字缺失的情况和部分关键字与地名重合的情况,直接通过匹配关键字来提取。显然这是一个漏洞很多的本方法,还需要想出办法来改进。
//识别“市”关键字
for (int i = 0; i < 5; i++) {
city_ += obj[i];
if (obj[i] == L'市') {
addr[c].city = city_;
return i + 1; break;
}
}
字符串转换函数:
从文件直接getline得到的字符串对汉字的处理比较奇怪,一个汉字需要占字符数组的两个单位,这给字符匹配和处理增加了很多麻烦。然后我就去百度惹(百度是镇滴好用!我爱csdn!)~发现通过把string转换成wstring后,再进行各种处理,会方便很多。因此就增加了两个转换函数。
以下是把string转换成wstring的函数:
wstring result;
//获取缓冲区大小,并申请空间,缓冲区大小按字符计算
int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0);
TCHAR* buffer = new TCHAR[len + 1];
//多字节编码转换成宽字节编码
MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len);
buffer[len] = ' '; //添加字符串结尾
//删除缓冲区并返回值
result.append(buffer);
delete[] buffer;
return result;
}
Part 5 : 计算模块接口部分的性能改进。
(1)记录在改进计算模块性能上所花费的时间,描述你改进的思路。
要改进计算模块性能,我觉得最重要的还是能学会调用地图API来进行匹配处理(或者还有另一种更简单的方法?),简化编程和节约时间空间。然鹅这个我还不会啊啊啊,给我时间,我觉得我阔以!
(2)展示一张性能分析图(由VS 2017/JProfiler的性能分析工具自动生成),并展示你程序中消耗最大的函数。
或许性能分析图是下面这个嘛?问了度娘就只查到了这个,应该是的吧……
CPU使用情况百分比
热路径和执行单个工作最多的函数
调用树(可见程序中消耗最大的函数)
Part 6 : 计算模块部分单元测试展示。
暂时还没有做单元测试这一项。待完成后再来补。
Part 7 : 计算模块部分异常处理说明。在博客中详细介绍每种异常的设计目标。每种异常都要选择一个单元测试样例发布在博客中,并指明错误对应的场景。
由于代码本身存在的bug问题,除了较为正常的未缺关键字的地址,异常情况的发生率还挺高的。特别是因为关键字引起的异常,比如:
1、关键字缺少。
“张三,福建福州闽13599622362侯县上街镇福州大学10#111.”这种情况下提取结果为{“姓名”:“张三”,“手机”:“13599622362”,“地址”:[“福建省”,“”,“福州闽侯县”,“上街镇”,“福州大学10#111.”]},使得市的提取失败,福州被匹配到县,间接导致县的提取失败。
2、关键字与地名重复。
“小美,北京市东15822153326城区交道口东大街1号北京市东城区人民法院.”这种情况下提取结果为{“姓名”:“小美”,“手机”:“15822153326”,“地址”:[“北京”,“北京市”,“东城区”,“交道”,“口东大街1号北京市东城区人民法院.”]},将详细地址错误匹配到上级地址中。