PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 15 | 30 |
Estimate | 估计这个任务需要多少时间 | 1400 | 1580 |
Developm | 开发 | 210 | 600 |
Analysis | 需求分析(包括学习新技术) | 150 | 150+ |
Design Spec | 生成设计文档 | 60 | 60 |
Design Review | 设计复审 | 10 | 10 |
Coding Standard | 代码规范(为目前的开发制定合适的规范) | 10 | 10 |
Design | 具体设计 | 60 | 120 |
Coding | 具体编码 | 210 | 600 |
Code Review | 代码复审 | 15 | 30 |
Test | 测试(自我测试,修改代码,提交修改) | 120 | 240 |
Reporting | 报告 | 60 | 60 |
Test Report | 测试报告 | 120 | 120 |
Size Measurement | 计算工作量 | 120 | 120 |
Postmortem & Process Improvement Plan | 事后总结,并提出过程改进计划 | 30 | 30 |
合计 | 1400 | 1580 |
解题思路:
一、思考 1、难度1!2!:字符串处理 2、难度3!:补全之后的字符串处理(补全之后,调用2!级别难度代码即可) 二、查找资料 1、学习了一下正则在python下的使用(主要匹配手机号、门牌号、路名等)。 2、下载了一个四级字典来暴力匹配省(直辖市自治区)、市、地区等等。实现过程:
一、思考(1!2!难度) 1、预处理:摘掉头部(','),去掉尾部('.'),拿出手机,放心食用。 2、省、市……分别封装,直到所下载字典的无法继续匹配的最低一级。 3、1中剩余部分,根据所到级数(记一个标志看到哪一级停止)来寻找对应关键字(镇、街道……),从而获得该级地址,若此时获得的为4级地址,则结束,余下部分即为5级地址。 4、根据输入难度,决定是否解析5级地址至7级。 5、3!的难度即为调用在线api之后,丢入2!难度处理代码(先得到5级地址,进而解析为7级地址)。 二、编码 1、面对样例编程的C++代码夭折。 2、Lv.5 $\rightarrow$ Lv.7 $\rightarrow$ 3!难度的python代码作为提交。 3、函数流图:4、关键接口(代码过于冗长,故以接口说明替代):
单元测试:
一、手动测试 2!李四,福建省福州13756899511市鼓楼区鼓西街道湖滨路110号湖滨大厦一层. '地址': ['福建省', '福州市', '鼓楼区', '鼓西街道', '湖滨路', '110号', '湖滨大厦一层'] 1!张三,福建福州闽13599622362侯县上街镇福州大学10#111. '地址': ['福建省', '福州市', '闽侯县', '上街镇', '福州大学10#111'] 2!王五,福建省福州市鼓楼18960221533区五一北路123号福州鼓楼医院. '姓名':'王五' 3!小美,北京市东15822153326城区交道口东大街1号北京市东城区人民法院. '地址': ['北京市', '北京市', '东城区', '交道口街道', '交道口东大街', '1号']}(调用api补全缺失最小一级,而输入串又有缺失。解决思路:可将五级地址丢入api补全以后再解析,同时将5级剩余的详细地址存住,最后加上7级解析剩余地址的结果,即为答案) 1!小陈,广东省东莞市凤岗13965231525镇凤平路13号. '手机': '13965231525'二、单元测试代码
class Test_For_UnitTest(unittest.TestCase): @classmethod def tearDownClass(self): pass @classmethod def setUpClass(self): pass def test_get_name(self): _in = open('./input.txt') _out = open('./output_name.txt') for _data, _label in zip(_in.readlines(), _out.readlines()): _predict = get_name(_data) self.assertEqual(_label.rstrip('\n'), _predict) _in.close() _out.close() def test_auto_geo_completion(self): _in = open('./input_broken.txt') _out = open('./output_completion.txt') for _broken in _in.readlines(): nw = _broken.rstrip('\n') ret = _auto_geo_completion(nw) _out.write(ret+'\n') _in.close() _out.close() def test_get_tel(self): _in = open('./input.txt') _out = open('./output_tel.txt') for _data, _label in zip(_in.readlines(), _out.readlines()): _predict = ''.join(get_tel(_data)) self.assertEqual(_label.rstrip('\n'), _predict) _in.close() _out.close()
PS:为什么有了单元测试代码,仍然还要手动测试呢?其实,单元测试的代码写起来很快,但是我解决报错问题解决了很久,仍然没有找到解决方案。报错的原因就是某些自定义函数和系统库均会报错(NameError)。吐了啊
class Test_For_UnitTest(unittest.TestCase): @classmethod def tearDownClass(self): pass @classmethod def setUpClass(self): pass def test_get_name(self): _in = open('./input.txt') _out = open('./output_name.txt') for _data, _label in zip(_in.readlines(), _out.readlines()): _predict = get_name(_data) self.assertEqual(_label.rstrip('\n'), _predict) _in.close() _out.close() def test_get_tel(self): _in = open('./input.txt') _out = open('./output_tel.txt') #_see = open('./see.txt') for _data, _label in zip(_in.readlines(), _out.readlines()): try: _predict = ''.join(get_tel(_data)) #_see.write(predict+'\n') self.assertEqual(_label.rstrip('\n'), _predict) except Exception as NameError: _in.close() _out.close() _in.close() _out.close() #_see.close() def test_auto_geo_completion(self): _in = open('./input_broken.txt') _out = open('./output_completion.txt') for _broken in _in.readlines(): nw = _broken.rstrip('\n') try: ret = _auto_geo_completion(nw) _out.write(ret+'\n') except Exception as NameError: _in.close() _out.close() _in.close() _out.close()
结果:
!!!我可以,我真的可以,它好了。其实,并没有好,因为我在try的时候尝试写文件(_see.txt,test_get_tel()代码中注释部分),结果发现文件里并没有东西,只是因为加了异常处理使得程序能够跑完而已。(表面ok,其实还是gg)性能改进:
1、主要是想把python写得短一点,葬送了4小时无果,不太熟悉此类代码如何减少编码复杂度。 2、因为输入的极短(每条地址信息),几乎没有考虑过时间复杂度,满屏的库操作。 3、函数开销(三幅图分别对应1,2,3难度,在命令行得到结果后,写入文件):可以看出3难度下,调用高德地图在线api时,程序的时间开销瞬间上涨。 参数解释: ncalls:表示函数调用的次数。 tottime:表示指定函数的总的运行时间,除掉函数中调用子函数的运行时间。 percall:(第一个 percall)等于 tottime/ncalls。 cumtime:表示该函数及其所有子函数的调用运行的时间,即函数开始调用到返回的时间。 percall:(第二个 percall)即函数运行一次的平均时间,等于 cumtime/ncalls。 filename:lineno(function):每个函数调用的具体信息。 参考: 大量数据结果:没想到就160条数据,就得跑这么久异常处理:
1、对于3!难度下,若样例前4级地址缺失,代码会报错无法运行,针对此在得知该条信息的需求难度时,若为3!,先进行补全。 2、字典的键值错误(KeyError),主要是通过最后一个样例发现(广东省……),于是增加了标志信息。 3、上面单元测试的异常处理,能算么?try: _json_info = {'姓名':'','手机':'','地址':[]} s = input() s = s[:len(s)-1] _op, s = get_op(s, '!') _op = int(_op) _name = get_name(s) #print(_name) _json_info['姓名'] = _name s = s[s.find(',')+1:] _tel = ''.join(get_tel(s)) #print(_tel) _json_info['手机'] = _tel s = clr(s,_tel) if (_op==1): _addr, _res = _analysis_lv5(s, dic) _addr.append(_res) _json_info['地址'] = _addr elif (_op==2): _addr, _res = _analysis_lv5(s, dic) _more_detail = _analysis_lv7(_res) _addr = _addr + _more_detail _json_info['地址'] = _addr else: _full_addr = _auto_geo_completion(s) #print('full_addr = ',_full_addr) _addr, _res = _analysis_lv5(_full_addr, dic) _more_detail = _analysis_lv7(_res) _json_info['地址'] = _addr + _more_detail except ValueError: print(json.dumps(_json_info, ensure_ascii=False)) else: print(json.dumps(_json_info, ensure_ascii=False))
心路历程和收获: