1.Github地址
GitHub地址
2.PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) |
---|---|---|
** Planning ** | 计划 | 20 |
· Estimate | · 估计这个任务需要多少时间 | 20 |
Development | 开发 | 1060 |
· Analysis | · 需求分析 (包括学习新技术) | 300 |
· Design Spec | · 生成设计文档 | 20 |
· Design Review | · 设计复审 | 20 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 |
· Design | · 具体设计 | 50 |
· Coding | · 具体编码 | 540 |
· Code Review | · 代码复审 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 60 |
Reporting | 报告 | 80 |
· Test Repor | · 测试报告 | 30 |
· Size Measurement | · 计算工作量 | 10 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 40 |
total | 合计 | 1160 |
3.设计与实现
设计过程
- 等级在输入的字符串中位置固定,在第一位,可以直接用序列号得到。
- 姓名位于“!”以及“,”之间,可以通过条件判断或者使用正则表达式匹配获得。
- 手机号长度固定为11位连续的数字,且手机号不会与其他的数字放在一起,也可以通过正则表达式获取。
对于剩下的地址,起初是想着暴力解答,通过关键字用正则表达式提取,再用条件判断进行筛选和分析,但是后来发现输入的地址中“省”和“市”等关键字是可以省略的,且关键字太多,无法完全考虑到,对于地址很难进行分割,就放弃了。而后听别的同学再讲用api,然后就临时去学了一下。由于我直接用高德地图api中的地理编码会造成返回数据不全,所以在这个的基础上改用逆地理编码,通过地理编码中的经纬度得到更加全的地址。如果是难度一和难度二,则于输入的地址进行比较,如果不能在输入的地址中找到则该项为空。
函数
函数名称 函数功能 getlevel(s) 获取等级 getname(s1) 获取姓名 gettelphone(s2) 获取电话号码 getaddress(s3) 调用api获取地址 finalget1(s3, position) 对于难度一的地址进行分析 finalget2(s3, position) 对于难度二的地址进行分析 finalget3(s3, position) 对于难度三的地址进行分析
实现过程
- 直接由输入字符串的第一个字符得到等级。
- 通过正则表达式
name = re.match(r'(.+?),', s1)
得到姓名。 - 通过正则表达式
tel = re.search(r'(\d{11})', s2)
得到电话号码,并将这些信息剔除得到只包含地址的字符串。
s3 = s2[:pos[0]] + s2[pos[1]:] #删除手机号码,得到只包含地址的字符串
- 使用高德地图api中的地理编码获得地址的经纬度
url = "https://restapi.amap.com/v3/geocode/geo?output=JSON&key=01a0be09080717e8fa1820123e5d2650&address=%s" % s3
res = requests.get(url)
res1 = json.loads(res.text) # 将得到的数据转化为json格式
location = res1['geocodes'][0]['location'] # 得到经纬度
- 由经纬度运用高德地图api中的逆地理编码得到完整的地址
re_url = "https://restapi.amap.com/v3/geocode/regeo?output=JSON&location=%s&key=01a0be09080717e8fa1820123e5d2650&radius=1000&extensions=base" % location
re_res = requests.get(re_url)
re_res1 = json.loads(re_res.text)
- 根据不同的等级对通过高德地图api得到的数据进行处理,其中由于详细地主没有任何规律,所以需要先将最后的详细地址先提取出来。
#等级一中详细地址的查找
x = re.search(r'.' + township, s3) #township为街道
if x == None:
township = ""
y = re.search(r'.' + district, s3) #district 为县
if y == None:
district = ""
z = re.search(r'.' + city, s3) #city 为市
if z == None:
city == ""
o = re.search(province, s3)
pos = o.span()
else:
pos = z.span()
else:
pos = y.span()
else:
pos = x.span() # 寻找s4
s4 = s3[pos[1]:-1] # 输入的末尾存在 "." 得到s4为详细地址
s5 = s3[:pos[1]] # s5为将详细地址取出后的其他地址
#先通过正则找到街道在字符串中的位置,在之后便是详细地址。
#若街道为空则向前寻找县,若仍然为空则再向前找市。
#等级二和等级三的详细地址寻找也类似与等级一,就不列出了。
将api得到的最终地址与原字符串中的地址进行比较,原字符串中若有存在则输出,无则输出空字符串。等级三则直接输出。
难点
- 对于等级一和等级二中,难以去判断api得到该级地址是否有在字符串中(api得到的地址为完整的地址名称,字符串输入的地址可能会省略如“省”、“市”等关键字,正则表达式搜索难以完全匹配),从而难以判断是否输出空字符串。
api中由经纬度返回的地址有时会存在误差,可能匹配到邻近的地址,使得与原本的地址完全不同,从而使输出完全不同。
性能分析
除去input函数,耗时最大的是对高德地图api的调用
def getaddress(s3):
url = "https://restapi.amap.com/v3/geocode/geo?output=JSON&key=01a0be09080717e8fa1820123e5d2650&address=%s" % s3 #使用高德地图api获得地址编码
res = requests.get(url)
res1 = json.loads(res.text)
location = res1['geocodes'][0]['location']
re_url = "https://restapi.amap.com/v3/geocode/regeo?output=JSON&location=%s&key=01a0be09080717e8fa1820123e5d2650&radius=1000&extensions=base" % location #逆地理编码
re_res = requests.get(re_url)
re_res1 = json.loads(re_res.text)
return re_res1
改进
对于难度一和难度二的地址不需要再次调用高德地图api中的逆地理编码,可以通过地理编码得到的地址用正则表达式和条件判断去判断地址,时间应该会快一点,不过需要考虑的东西太多。
单元测试
单元测试代码
def finalget1(s3, position):
# "直辖市/省(省级)","直辖市/市(地级)","区/县/县级市(县级)","街道/镇/乡(乡镇级)","详细地址"
province = position['regeocode']['addressComponent']['province']
city = position['regeocode']['addressComponent']['city']
district = position['regeocode']['addressComponent']['district']
township = position['regeocode']['addressComponent']['township']
if province == '北京市' or province == '天津市' or province == '重庆市' or province == '上海市':
city = province
province = province[:-1]
x = re.search(r'.' + township, s3)
if x == None:
township = ""
y = re.search(r'.' + district, s3)
if y == None:
district = ""
z = re.search(r'.' + city, s3)
if z == None:
city == ""
o = re.search(province, s3)
pos = o.span()
else:
pos = z.span()
else:
pos = y.span()
else:
pos = x.span() # 寻找s4
s4 = s3[pos[1]:-1] # 输入的末尾存在 "."
s5 = s3[:pos[1]]
if len(district) == 0:
district = ""
if len(city) == 0:
city = ""
if city != "" or city != None:
city_test = city[:2]
test_c = re.search(city_test, s5)
if test_c == None:
city = ""
a = re.search(district, s5)
if a == None:
district = ""
b = re.search(township, s5)
if b == None:
township = ""
in_location = [province, city, district, township, s4]
return in_location
测试样例
1!尉迟根,吉林白城镇赉县嘎什根乡103县道中心小学校那林分13015613140校镇赉县嘎什根乡那林村村委会.
1!高蛾,陕西省延安市吴起县铁边城镇王洼子分理处陕西15177996133吴起农村合作银行王洼子乡农村信用社.
1!宦册,辽宁省葫芦岛杨家15677738100杖子经济开发区局前新26号楼.
1!公西堕,福建省福州市鼓楼区鼓东街道庆城路48号鼓楼13060105892区庆城幼儿园.
1!家按犯,西藏自治区昌都市卡若区城关镇214国道城关镇嘎15347650776东街社区居民委员会.
1!姬苇,湖南省长沙市芙蓉区朝阳街街道曙光15205255175北路长铁向韶村第23栋.
1!宓额绘,陕西省商洛市商南县312国道商南县富水镇15877101636茶坊村工会委员会.
1!祖染,青海省海西蒙古族藏族自治州乌兰县15095860003茶卡镇交通街6-2号茶卡镇四村综合服务中心.
1!谷梁箱,浙江省绍兴市诸暨15025820635市王家井镇南三环路后陈村委会.
1!鞠高秕,广东省汕尾市城区红草镇汕尾市城区红草镇拾和村民委15680550741员会.
代码说明
对由高德地图api获得的地址进行分析判断,判断该地址中各个级别的地址是否有存在于原字符串,有则保留,无则将该地址设置为空字符串。(难度等级为一)
异常处理说明
部分地址由于经纬度的误差,使得api返回的地址出错。(或者是因为该地方有多个名字,输入的和高德地图的名字不一样,造成返回的地址有误)
样例
输入3!汝舟孙,贵州省修文县龙岗社区15766780930服务中心阳明西路196号龙岗居委会.
输出{"姓名": "汝舟孙", "手机": "15766780930", "地址": ["贵州省", "贵阳市", "修文县", "龙岗社区服务中心", "人民南路", "196号", "龙岗居委会"]}
正确答案{"姓名": "汝舟孙", "手机": "15766780930", "地址": ["贵州省", "贵阳市", "修文县", "龙岗社区服务中心", "阳明西路", "196号", "龙岗居委会"]}
END
第一次用python写代码,太难了。