第一次个人编程作业

github仓库地址:
http://github.com/suweihuan079243/031702436]

PSP表格

PSP2.1 | Personal Software Process Stages |预估耗时(分钟)|实际耗时(分钟)

  • | :-: | -:
    Planning |· 计划| 1440|1980|
    · Estimate | · 估计这个任务需要多少时间 |1440| 1980
    Development| · 开发| 600|1000|
    · Analysis|· 需求分析 (包括学习新技术)|180|180|
    · Design Spec | · 生成设计文档 | 1440||
    · Design Review|· 设计复审 |1440|
    · Coding Standard| · 代码规范 (为目前的开发制定合适的规范) |30 |30|
    · Design|· 具体设计 |120|180|
    · Coding|· 具体编码)|600||
    · Code Review |· 代码复审|60 ||
    · Test| · 测试(自我测试,修改代码,提交修改) |180|
    · Reporting|· 报告 | ||
    · Test Repor|· 测试报告|||
    · Size Measurement|· 计算工作量|||
    · Postmortem & Process Improvement Plan|· 事后总结, 并提出过程改进计划|60||
    · |· 合计|7560||

# 预备知识学习 #

  1. JSON
由于本次的输入输出需要使用到JSON,所以迫不得已去学习了一下,以下是我学习json的一些资源分享

2.正则表达式

需要利用正则表达式分割信息中的level、name、phoneNumber
  • 这是在知乎上看到的github上的一个超过2w星的正则表达式学习项目

https://github.com/ziishaned/learn-regex

  • 一个在线测试正则表达式的平台

https://regex101.com/

解题过程

本次编程作业的解题过程真的太难了(我太菜了),多亏我的一位热心同学全程给予我很多帮助,帮我配置gradle和教我git的使用(虽然我每次commit都是让他帮我弄),还有编程过程遇到的一些问题占用了他很多时间,非常感谢这位热心同学.

思路

  1. 由于涉及到杂乱字符串信息的提取,所以想到用正则表达式分割。
  2. 题目要求里有部分地址缺失,有点难定义一个完整的正则式来处理所有情况,所以想到通过全国 地图信息(省市县镇)来进行匹配。该地图为一个json文件,每级地址(除最后详细地址)下都有一个数组包含其下辖地址,通过逐级匹配来分割信息。
  3. 调用高德地图api,可惜不会。

设计实现过程

主要类

  • 个人信息类Person
  • 地图信息类MapData
  • 分割信息工具类Trim
  • Province类
  • City类
  • County类
  • Town类
  • Street类

主要函数 # :

  • MapData.readMap():读取地图信息
  • void Trim.setNewInformation(String information):读取个人信息
  • void Trim.trimPhoneNumber():分割电话
  • void Trim.trimLevel():分割等级和姓名
  • void Trim.trimProvince():分割省份
  • void Trim.trimCity(Province province):分割城市
  • void Trim.trimCounty(City city):分割县级地区
  • void Trim.trimTown(County county):分割镇级地区
  • void Trim.trimStreet():分割镇以下地区
  • String Trim.trimInformation:去掉比较过的信息并返回新的信息

关键代码

public void trimProvince() {
try {				
MapData.readMap();
} catch (IOException e) {
e.printStackTrace();
}
person.setName(this.personName);//初始化姓名
person.setPhoneNumber(this.phoneNumber);//初始化手机
// 福建福州市鼓楼区鼓西街道湖滨路110号湖滨大厦一层.
String provinceInformation = this.newInformation.substring(0, 2);//福建

String provinceName =null;

for (Province province : MapData.getProvinces()) {
   provinceName = province.getProvinceName().substring(0, 2);//福建
if (provinceInformation.equals(provinceName)) {

if (provinceName.equals("北京") || provinceName.equals("重庆") ||
provinceName.equals("天津") ||provinceName.equals("上海")){
//
person.setProvince(province.getProvinceName());
} else {
person.setProvince(province.getProvinceName());
this.newInformation = trimInformation(this.newInformation, province.getProvinceName());
}
this.province=province;
break;
}
}
if(this.province!=null){
trimCity(this.province);
}else {
person.setProvince("""");
}
}
  1. 分割省份:先读取整个地图数据,截取信息的前两位用于省份匹配,遍历地图数据的省份,将provinceName与真实省名比较,如果相同则将信息与省名相同的部分去掉返回新的信息,并设置个人的省份,(ps:如果为直辖市,则只设置省份信息,方便后续用于城市信息的匹配),然后继续匹配城市。

     if(this.city!=null){
       trimCounty(this.city);
     }else{
      person.setCity("""");
     if(this.province!=null){
      List<City> cityList = this.province.getCities();
      for(City city:cityList){
      trimCounty(city);
      }	 } }
    
  2. 由于城市以下的地址可能为空,所以匹配完进行判断。如果不为空继续判断,否则通过去遍历此
    省份的所有城市去匹配其下辖的县级地区,后面类似。

     private void trimStreet() {
     if (this.level == 1) {
     person.setRestAddress(this.newInformation);//五级地址直接将镇以下赋值
     } else if (this.level == 2 || level == 3) {
     String regex1 = "(\D+)(\d+号)";//匹配路名和门牌号
     Pattern pattern = Pattern.compile(regex1);
     Matcher matcher = pattern.matcher(newInformation);
     String restAddress = null;
     if (matcher.find()) {
     restAddress = matcher.replaceFirst("");
     this.newInformation = matcher.group();
     String regex2 = "\d+号";
     String gateNumber = null;
     String roadName = null;
     Pattern pattern1 = Pattern.compile(regex2);
     Matcher matcher1 = pattern1.matcher(this.newInformation);
     if (matcher1.find()) {
     gateNumber = matcher1.group(0);//匹配门牌号
     roadName = matcher1.replaceAll("");//匹配路名
     }
     if(roadName!=null){
     person.setRoadName(roadName);
     }else {
     person.setRoadName("""");
     }
     if(gateNumber!=null){
     person.setGateNumber(gateNumber);
     }else{
     person.setGateNumber("""");
     }
     if(restAddress!=null){
     person.setRestAddress(restAddress);
     }else{
     person.setRestAddress("""");
     }
     }
     }
    
  3. 根据等级处理镇以下的地址信息,如果level=1,直接将镇以下的地址信息全部输出;如果是level2&level3,就继续利用正则分割为路、门牌号、详细地址(虽然我不知道是不是所有例子的门牌号都是以号结尾)

性能分析


说真的我看不懂更别说改进了,能有结果就不错了

异常处理说明

@Test
public void testTrimLevel(){
    Trim trim=new Trim();
    trim.setNewInformation("1!宗衬缝,湖南省长沙市浏阳市古港镇024乡道古港镇梅田湖村村民委员15590409121会.");
    trim.trimLevel();
    System.out.println(trim.getLevel());
}

public void trimLevel() {

    String regexLevel = "[!,]";

    String[] split = this.newInformation.split(regexLevel);

    this.level = split[0];

    personName = split[1];

    this.newInformation = split[2];
    person.setName(this.personName);
}

一开始level定义为int类型,截取后通过Integer.parseInt()转为int类型,后面改来改去不知道为什么就会出现NumberformatException,找了半天找不到原因。就只好level定义为String类型就好了。

	try {
        MapData.readMap();
    } catch (IOException e) {
        e.printStackTrace();
    }
    String provinceInformation = this.newInformation.substring(0, 2);
    List<Province> provinceList = MapData.getProvinces();
    **for (Province province : provinceList) **

一开始每级的分割地址*号部分经常出现nullpointerexception,原因是忘了先读取地图。

大概就是这样,写了将近两天才勉强可以匹配部分情况,评测同学有点耐心将就着看吧。通过这次和以前完全不一样的作业,发现大佬们平时做的事情是真的牛批,天天群里都是99+说一些自己根本看不懂的东西,发现自己要学的东西还有很多,然后还有结对编程要做,浑身疼,洗洗睡了。

原文地址:https://www.cnblogs.com/swh1148318751/p/11537575.html