第一次编程作业

泪湿孤枕 提交于 2019-11-30 16:02:19

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

代码说明

对由高德地图api获得的地址进行分析判断,判断该地址中各个级别的地址是否有存在于原字符串,有则保留,无则将该地址设置为空字符串。(难度等级为一)

异常处理说明

部分地址由于经纬度的误差,使得api返回的地址出错。(或者是因为该地方有多个名字,输入的和高德地图的名字不一样,造成返回的地址有误)

样例

输入3!汝舟孙,贵州省修文县龙岗社区15766780930服务中心阳明西路196号龙岗居委会.
输出{"姓名": "汝舟孙", "手机": "15766780930", "地址": ["贵州省", "贵阳市", "修文县", "龙岗社区服务中心", "人民南路", "196号", "龙岗居委会"]}
正确答案{"姓名": "汝舟孙", "手机": "15766780930", "地址": ["贵州省", "贵阳市", "修文县", "龙岗社区服务中心", "阳明西路", "196号", "龙岗居委会"]}

END

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!