1.GitHub
< https://github.com/hsthy/031702426>
2.PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 20 |
· Estimate | · 估计这个任务需要多少时间 | 20 | 20 |
Development | 开发 | 240 | 840 |
· Analysis | · 需求分析 (包括学习新技术) | 120 | 100 |
· Design Spec | · 生成设计文档 | 10 | 10 |
· Design Review | · 设计复审 | 10 | 15 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | 15 |
· Design | · 具体设计 | 30 | 40 |
· Coding | · 具体编码 | 120 | 380 |
· Code Review | · 代码复审 | 60 | 40 |
· Test | · 测试(自我测试,修改代码,提交修改) | 60 | 240 |
Reporting | 报告 | 100 | 120 |
· Test Repor | · 测试报告 | 40 | 60 |
· Size Measurement | · 计算工作量 | 20 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 40 | 40 |
· 合计 | 360 | 980 |
3.计算模块接口的设计与实现过程
写在最前面的是我的设计思路。
切分难度等级和姓名、手机号太简单了这里就不说了。下面只讲地址如何处理。
在我们发布作业之前,柯逍老师班级发布这道题的时候,我就去看了下他们题目,顺便还写了点,不过由于上周在爆肝花朵识别就没继续写。
看到题目的第一反应是调API解决。(这就是我在PSP表格里预期过于自信的原因)在上篇博客提到过利用百度智能云TTS的API,那会儿顺便看了下百度智能云的位置DuMap服务。
DuMap给了几个接口。初步想法是调用地理编码API将题目所给的文字位置信息转化为经纬度,然后调用逆向地理编码API将经纬度转回JSON格式的地理信息。所以预估题目用不了三小时就好了。。。。。。然后发现我天真了。。。。。。精度真的很差(辣鸡百度)。这个方法行不通后,我发现他还有个行政区划区域检索的接口,不过同样辣鸡。。。。。。举个栗子,写博客这晚我去的铜盘智园羽毛球馆,这是一个相对精确的地址,但是在这个API请求结果会跳出2个POI。。。像福州大学旗山校区玫瑰园食堂,他能返回好几个POI。。。。。。所以这个方法也不行。
遂转战高德地图API,同样辣鸡。地理(正向/逆向)编码的API精度不够,行政区划的API仅仅允许一个关键词。。。而且是向下查询毫无卵用(其实还是有点用的,后面会提到高德的这个行政区划API)
接下来就是最后实现的方法。这里的主要思路是查询这个表全国省市区县街道json\pcas-code.json,下载地址https://www.dssz.org/3385070.html 这个json其实可以通过上文提到的高德行政区划的API爬到或许更新的(鬼知道高德的数据新不新啊)数据。
这里放一下请求地址:
https://restapi.amap.com/v3/config/district?keywords=地址关键字&subdistrict=2&key=
省 市 区(县) 街道 这前四级都可以通过查表实现。每次通过字符串切片得到字符串前两个字符与四级行政区划json表格内容进行比对,过程就是一些for循环(缺失的情况下需要嵌套的for),最后得到第五级详细地址,在难度一中就完成了,在难度二中,需要对难度一的第五级详细地址用正则表达式进行匹配。具体可以看后面的代码。
而难度三,由于没有API帮助,这里无法实现第四级,即街道这一级缺失的处理。(这里包括了同时缺失第四级和其他级别的情况)。难度三这里处理方法是多层for循环嵌套(数据量还是可以接受的查询速度不会很慢)尽管这个解法很水很水很水,但是最终还是得到了115/125(天枢星)||1094.8000000000588/1151(最终版测试工具)分数。
#定义标准答案的格式,名字+手机+七级地址
class Result:
name = ""
phone = ""
province = ""#直辖市/省(省级)
city = ""#直辖市/市(地级)
area = ""#区/县/县级市(县级)
town = ""#街道/镇/乡(乡镇级)
street = ""#路名
number = ""#门牌号
building = ""#详细地址
#获取电话
def getphone(s):
pattern = re.compile(r'1\d{10}')
match = pattern.search(s)
try:
phone = match.group(0)
except AttributeError:
print("输入的手机号格式不正确")
return phone
#去除混杂在中间的电话,获取混合的地址
def getaddress(s,phone):
addressList=s.split(phone)
address=""
address=address.join(addressList)
address=address[:-1]#切片去除句点
return address
#去除字符串头部指定的子串
def cutdown(origin,child):
limit=len(child)
i = 0
while i < limit:
if origin[i] != child[i]:
break
i = i + 1
return origin[i:]
def segementFive(add,res,jd):
#直辖市/省(省级)
match=add[:2]
#print("匹配",match)
for itemProvince in jd:
if re.search(match,itemProvince["name"]):
res.province = itemProvince["name"]
cityList = itemProvince
#print(res.province)
add=cutdown(add,res.province)#混合地址去除省份
#判断第一级是否为直辖市,若是,添加回字符串(第二级用
for direct in ["北京","上海","天津","重庆"]:
if direct == res.province:
add = res.province + add
break
if res.province == "":#目前台湾暂时没有数据
return
#-------------------------------------------------------------------------
#直辖市/市(地级)
flagCity=0#默认没有查找到
match=add[:2]
for itemCity in cityList["children"]:
if re.search(match,itemCity["name"]):
flagCity=1
res.city = itemCity["name"]
#print(res.city)
add = cutdown(add,res.city)
areaList = itemCity
break
#-------------------------------------------------------------------------
#区/县/县级市(县级)
match=add[:2]
flagArea=0
if(flagCity==1):
for itemArea in areaList["children"]:
if re.search(match,itemArea["name"]):
flagArea=1
res.area=itemArea["name"]
#print(res.area)
add=cutdown(add,res.area)
townList=itemArea
break
else:#处理市级缺失情况下的县级查找
for itemCity in cityList["children"]:
for itemArea in itemCity["children"]:
if re.search(match,itemArea["name"]):
res.area=itemArea["name"]
#print(res.area)
add = cutdown(add,res.area)
townList=itemArea
flagArea=1
break
else:
continue
break
#---------------------------------------------------------------------
#街道/镇/乡(乡镇级)
match=add[:2]
if (flagArea==1):
for itemTown in townList["children"]:
if re.search(match,itemTown["name"]):
res.town = itemTown["name"]
#print(res.town)
add=cutdown(add,res.town)
break
else:#处理县级缺失情况下的乡镇级查找
for itemArea in areaList["children"]:
for itemTown in itemArea["children"]:
if re.search(match,itemTown['name']):
res.town=itemTown["name"]
#print(res.town)
add=cutdown(add,res.town)
break
else:
continue
break
#---------------------------------------------------------------------
res.street=add#在五级地址中使用street作为详细地址
def segementSeven(detail,res):
add=detail
pattern=re.compile(r'(.*?[街])|(.*?[道])|(.*?[路])|(.*?[巷])|(.*?[大街])|(.*?[街道])')
#pattern= re.compile(r'.+(路|街|巷|桥|道){1}')
match = pattern.search(add)
if(match):
res.street = match.group(0)
else:#可能存在缺失街道
res.street = ""
#print(res.street)
add = cutdown(add,res.street)
pattern=re.compile(r'(.*?[号])')
#pattern = re.compile(r'.+(号){1}')
match = pattern.search(add)
if(match):
res.number = match.group(0)
else:#可能存在缺失门牌号
res.number = ""
#print(res.number)
add = cutdown(add,res.number)
res.building = add
#print(res.building)
def enhancement(add,res,jd):
#直辖市/省(省级)
match=add[:2]
#print("匹配",match)
flagProvince=0#默认省级没有找到
for itemProvince in jd:
if re.search(match,itemProvince["name"]):
flagProvince=1
res.province = itemProvince["name"]
cityList = itemProvince
add=cutdown(add,res.province)#混合地址去除省份
#判断第一级是否为直辖市,若是,添加回字符串(第二级用
for direct in ["北京","上海","天津","重庆"]:
if direct == res.province:
add = res.province + add
break
#-------------------------------------------------------------------------
#直辖市/市(地级)
flagCity=0#默认没有查找到
match=add[:2]
if(flagProvince==1):
for itemCity in cityList["children"]:
if re.search(match,itemCity["name"]):
flagCity=1
res.city = itemCity["name"]
add = cutdown(add,res.city)
areaList = itemCity
break
else:#处理省级缺失情况下的市级查找
for itemProvince in jd:
for itemCity in itemProvince["children"]:
if re.search(match,itemCity["name"]):
flagCity=1
flagProvince=1
res.province=itemProvince["name"]
res.city=itemCity["name"]
add=cutdown(add,res.city)
areaList=itemCity
#-------------------------------------------------------------------------
#区/县/县级市(县级)
match=add[:2]
flagArea=0
if(flagCity==1):
for itemArea in areaList["children"]:
if re.search(match,itemArea["name"]):
flagArea=1
res.area=itemArea["name"]
add=cutdown(add,res.area)
townList=itemArea
break
elif(flagCity==0 and flagProvince==1):#处理省级不缺失但是市级缺失情况下的县级查找
for itemCity in cityList["children"]:
for itemArea in itemCity["children"]:
if re.search(match,itemArea["name"]):
flagCity=1
flagArea=1
res.city=itemCity["name"]
res.area=itemArea["name"]
add = cutdown(add,res.area)
townList=itemArea
break
else:
continue
break
else:#(flagCity==0 and flagProvince==0):#处理省级缺失并且市级缺失情况下的县级查找
for itemProvince in jd:
for itemCity in itemProvince["children"]:
for itemArea in itemCity["children"]:
if re.search(match,itemArea["name"]):
flagProvince=1
flagCity=1
flagArea=1
res.province=itemProvince["name"]
res.city=itemCity["name"]
res.area=itemArea["name"]
add=cutdown(add,res.area)
townList=itemArea
break
else:
continue
break
if(flagProvince==1):
break
#---------------------------------------------------------------------
#街道/镇/乡(乡镇级)
match=add[:2]
flagTown=0#默认没有查找到
if (flagArea==1):
for itemTown in townList["children"]:
if re.search(match,itemTown["name"]):
res.town = itemTown["name"]
#print(res.town)
add=cutdown(add,res.town)
break
elif(flagArea==0 and flagCity==1):#处理市级不缺失但县级缺失情况下的乡镇级查找
for itemArea in areaList["children"]:
for itemTown in itemArea["children"]:
if re.search(match,itemTown['name']):
res.area=itemArea["name"]
res.town=itemTown["name"]
#print(res.town)
add=cutdown(add,res.town)
break
else:
continue
break
else:#(flagArea==0 and flagCity==0)处理市级缺失并且县级缺失情况下的乡镇级查找
for itemCity in cityList["children"]:
for itemArea in itemCity["children"]:
for itemTown in itemArea["children"]:
if re.search(match,itemTown["name"]):
flagCity=1
flagArea=1
flagTown=1
res.city=itemCity["name"]
res.area=itemArea["name"]
res.town=itemTown["name"]
add=cutdown(add,res.town)
break
else:
continue
break
if(flagCity==1):
break
#---------------------------------------------------------------------
pattern=re.compile(r'(.*?[街])|(.*?[道])|(.*?[路])|(.*?[巷])|(.*?[大街])|(.*?[街道])')
#pattern= re.compile(r'.+(路|街|巷|桥|道){1}')
match = pattern.search(add)
if(match):
res.street = match.group(0)
else:#可能存在缺失街道
res.street = ""
#print(res.street)
add = cutdown(add,res.street)
pattern=re.compile(r'(.*?[号])')
#pattern = re.compile(r'.+(号){1}')
match = pattern.search(add)
if(match):
res.number = match.group(0)
else:#可能存在缺失门牌号
res.number = ""
add = cutdown(add,res.number)
res.building = add
def formatFive(res,dat):
dat["姓名"]=res.name
dat["手机"]=res.phone
dat["地址"].append(res.province)
dat["地址"].append(res.city)
dat["地址"].append(res.area)
dat["地址"].append(res.town)
dat["地址"].append(res.street)
def formatSeven(res,dat):
dat["姓名"]=res.name
dat["手机"]=res.phone
dat["地址"].append(res.province)
dat["地址"].append(res.city)
dat["地址"].append(res.area)
dat["地址"].append(res.town)
dat["地址"].append(res.street)
dat["地址"].append(res.number)
dat["地址"].append(res.building)
def solution(sourceStr,JD):#参数是原始字符串和js数据表
#用于输出的json
data={
"姓名":"",
"手机":"",
"地址":[]
}
result = Result()#实例化结论格式
s = ""
s=sourceStr
level = s.split("!")[0]#获取本条输入的难度
level=eval(level)
s=s.split("!")[1]#原始输入去掉"难度!"
result.name = s.split(",")[0]#获取姓名
s=s.split(",")[1]#原始输入剩余电话与地址
phonenumber = getphone(s)#获取电话
result.phone = phonenumber
address=getaddress(s,phonenumber)#address为初步的混合地址
if level==1:
segementFive(address,result,JD)
formatFive(result,data)
elif level==2:
segementFive(address,result,JD)
segementSeven(result.street,result)
formatSeven(result,data)
else:
enhancement(address,result,JD)
formatSeven(result,data)
jsonresult=json.dumps(data,ensure_ascii=False)
print(jsonresult)
事实上,运行pylint分析代码后有一个warning不是很明白。eval干嘛不能用啊?
4.计算模块接口部分的性能改进
因为是循环输入的,1151条数据,所以输入部分肯定是消耗最大的。。。改不动改不动
5.计算模块部分单元测试展示
展示出项目部分单元测试代码,并说明测试的函数,构造测试数据的思路。并将单元测试得到的测试覆盖率截图,发表在博客中。**(6')
部分测试数据
1!皇甫享,安徽宣城郎13734164891溪县飞鲤镇011乡道西三立村村委会.
1!家按犯,西藏自治区昌都卡若区城关镇214国道城关镇嘎东街社区居民委员15347650776会.
1!席赠,湖南省长沙市雨花区黎托街道黎托15224968346乡川河村雨花区托溪小学.
1!淳于象,辽宁丹东凤城市刘家河镇304国道徐家台村委13986910893会.
1!成偶,山西省吕梁岚18918500295县王狮乡209国道阳湾明德小学.
1!何东,北京东城13297814858区朝阳门街道南小街59号竹杆胡同小区.
1!满哪俊,福建福州仓山区临江街道工农路36号下池小区11号15384414182楼.
1!钱僻苍,安徽省合肥市瑶海区合肥龙岗综合经济开发区海洲景秀世家2期13001981786.
1!阳吟,上海市绿华18970386517镇华西村村委会.
1!施裕槐,上海普陀区大13743250056渡河路1927弄真北新村三街坊2号楼.
1!农咧,江苏省扬州市江都区15058550687大桥镇昌勋村村委会.
1!咸陡隐,江苏省苏州吴江区平望镇新业织造有限公司吴江区平望镇双浜村村民委员13184142847会.
1!池桑炉,天津市河西区友谊路街道黑牛城道平江南里30号丽13739936363枫酒店.
1!卜畸,天津东丽区丰年村街道丰年村街道办事处常熟里社18974264425区居民委员会.
1!左悯渣,浙江省湖州南浔区湖盐公路花城村13938948912村委会.
1!曹租,13286764387北京市丰台区张郭庄南路11号张郭庄小区.
1!谈艇,上海市黄浦区豫园街道方浜西路10号方西居委18839721688会.
1!白粥屠,山西省晋中市平遥县兴民街18号新南堡小学新15363389322南堡供销综合门市部.
1!敖堡,山东烟台蓬莱市南王街道15759233074芝山路中共大宁家村支部委员会.
1!邴拆,重庆北碚区龙凤桥街道15242716859龙凤桥街龙凤2村.
1!胥怕摩,天津市河东区成林道63号天津工业15567749658大学.
1!胥卫忍,福建省南平市邵武市卫13017035415闽镇谢坊村耕山队.
1!詹持,山西省晋中市平遥县古陶镇永安南路闫壁村委13346009866会.
1!卜寸潜,河北保定竞秀区东风街道西大园西街24号13328693915.
1!第五昌因,黑龙江省鸡西市密山市裴德镇兴利村15109633363农机服务站.
1!满虏,河南省焦作市山阳区中星街道焦辉路中马村巧莲大型15165434173弹花.
2!郦暗祸,北京市门头沟区东辛房街道滑15964374932石道78号.
2!罗挚,上海市长宁13866840508区虹桥街道虹桥路虹桥小区.
2!居刁员,四川省成都邛崃市火井镇状元路185号高场社区居委15182872302会.
2!蒲诚,广东省汕头市濠13798786108江区达濠街道海旁路10号达濠派出所.
2!蒯哎葫,山西太原市尖草坪区15247416699迎新街道新顺南大街南固碾村委会.
2!微生句,广西壮族自治区桂林市七星15605131954区七星区街道金星路2号矿地院.
2!茅参,上海市嘉定区马13347914736陆镇嘉新公路1157号樊家村1256号楼.
2!周厘倾,北京13274312770市石景山区鲁谷街道鲁谷大街七星园北区24号楼.
2!寿佳,湖13221817716南益阳赫山区春嘉路6号.
2!柳吻,辽宁省大连市中山区青泥13013864707洼桥街道上海路45号宏孚大厦苏宁易购.
2!宋俗管,广东省珠海市15925966933三灶镇求知路23号鱼林小学.
2!沃顽敷,上海市徐汇区华泾镇华发15005036921路99号明丰新纪苑.
2!田社耘,黑龙江齐齐哈尔市龙沙区湖滨街道园18623684309建街51号园艺小区.
2!路输,江苏省沭阳县周集13031622960乡人民路1号沭阳县周集乡人民政府.
2!钟离越,浙江舟山岱山县高亭镇沿港西路209号闸口社区13454791025.
2!嵇陨协,内蒙古自治区锡林郭勒盟二连浩特市二连边境经济技13182128688术合作区新华大街8号远恒木业.
2!宿冕,辽宁省大连市沙河口区兴工街道如意街46号大14777396416连罗斯福广场A座.
2!姚帮,广东省汕头市潮南区峡山街道峡山义英义华路136号莎13184626238丹服饰.
2!连一渊,北京东城区安定门街道分15866710776司厅胡同17号.
2!巫马锚,浙江省杭州15166205701市余杭区临平街道星火南路23号星火办公楼.
3!符乡,安徽大观区菱湖街道宜园13281503317路80号.
3!褚佳,浦13447146058东新区惠南镇靖海路440号靖海桥大楼.
3!单轿组,上海市浦东新区博山路12号泾东新15155759742村.
3!嵇陨协,内蒙古自13182128688治区锡林郭勒盟新华大街8号远恒木业.
3!周厘倾,北京市石景山13274312770区鲁谷大街七星园北区24号楼.
3!濮婚时,广西壮族自治区桂林市七星区育才13602947448路15号北院广西师大育才校区.
3!柏雅蚜,长宁区周家桥街道武夷路718号武夷13757741271花园722号楼.
3!汝舟孙,贵州省修文县龙岗社区15766780930服务中心阳明西路196号龙岗居委会.
3!荀祈,上海市马15934800449陆镇宝安公路2888号包桥小区.
3!蒯刑浦,白城市洮南市团结街道兴安南街5566号安泰社区公13949401891共事务服务中心.
3!羿暴蛆,浙江省13408790784温州市龙湾区上江路65号溢香厅国际宴会中心.
3!丰缓,滨海新区新城镇新城村东里5号新城13608320376中学.
3!连一渊,东城区安定门街道分司厅15866710776胡同17号.
3!艾堤,北京市海淀区阜成15938433933路八宝庄小区8号楼.
3!廉捷咏,浙江省上城区紫阳街道太庙巷62号紫阳学前教18999108285育集团.
3!华壳腰,福建省西陂街道西陂路286号西15072977042山小区.
3!宿冕,辽宁省沙河口区兴工街14777396416道如意街46号大连罗斯福广场A座.
3!汲者,江苏灌13555806486南县田楼镇新盘村新盘幼儿园.
3!佘器,福建莆田市仙游县仙东13327922135村仙东小学.
3!墨笑,四平市平东街道国测小区8号13185319734楼.
3!夹谷抡枯,甘肃城关区皋兰路街道皋兰18795320124路210号郑家台小区.
3!孙旗乖,13366755810白城市洮北区长庆南街65号.
3!刁夹箭,陕西省安康市平利县湖南13402846657路纸坊沟村卫生室.
3!年磅,贵州贵15649587434阳米坪乡云湾村村民委员会.
3!罗挚,上海虹13866840508桥街道虹桥路虹桥小区.
3!蔺脚贺,湖南省娄底市冷水江市石槽村三尖镇15581828223人民政府.
6.计算模块部分异常处理说明
#获取电话
def getphone(s):
pattern = re.compile(r'1\d{10}')
match = pattern.search(s)
try:
phone = match.group(0)
except AttributeError:
print("输入的手机号格式不正确")
return phone
举个栗子,这里异常处理是防止输入手机号不正确产生的问题