第一次个人编程作业

第一次个人编程作业

一、仓库地址

二、PSP表格

PSP2.1 Personal Software
Process Stages
预估耗时(min) 实际耗时(min)
Planning 计划 40 30
Estimate 估计这个任务需要多少时间 40 30
Development 开发 1800 2000
Analysis 需求分析
(包括学习新技术)
400 600
Design Spec 生成设计文档 30 30
Design Review 设计复审 30 40
Coding Standard 代码规范
(为开发制定合适的规范)
30 45
Design 具体设计 120 180
Coding 具体编码 240 270
Code Review 代码复审 120 120
Test 测试
(自我测试,修改,提交修改)
120 180
Reporting 报告 60 80
Test Report 测试报告 20 25
Size Measurement 计算工作量 10 15
Postmortem & Process
Improvement Plan
事后总结
并提出过程改进计划
40 60
合计 3100 3705

三、算模块接口的设计与实现过程

(写在前面的铺垫。因为本人代码能力实属菜鸡,c++和c都有许多题目不会打。在得知Java和Python的正则可能比较好处理后,再加上python选修给我的打击,我选择了Java来解决这道问题。这也给我后面被json缠绕的痛苦埋下伏笔.........

1.解题思路:

看到题目后首先判断需要用不同的正则表达式来取出需要的姓名、电话、地址。用字符串有关函数来进行切割,将字符串数据转换成json文件。数据的重点是电话是混在一串地址中,并且地址中可能还有门牌号之类的数据。但是题目已经确定手机号码一定不会和地址中的数字相邻,算是避免掉了稍微麻烦一点的情况。通过正则匹配,取出感叹号之前的字符包括感叹号,再通过字符串的substring()函数把感叹号切割掉。后来想到更简洁的正则,直接用([1])取出在字符串最前的数字。判断感叹号前的数是1还是2来选择五级地址处理还是七级地址处理。并且先从简单的情况入手,排除掉缺失省市关键字的情况还有地址缺失需要补全的难度。

2.解题步骤:

1.主函数中写好输入输出的格式,在readline()函数中对每一行的地址数据进行操作。通过函数调用,用正则表达式分离出x!、姓名、手机、地址的字符串。
2.将处理出来的姓名和手机先放着,通过取出的x的值来选择处理地址的函数。
3.处理地址的函数中再用正则表达式来分离省市县等具体的地址。
4.处理地址的函数返回值是动态数组。在主函数调用处理地址函数后返回主函数调用 getjson函数把字符串转成map数据类型。
5.在主函数转换成json数组。

参考资料

[1]https://blog.csdn.net/superSubfn/article/details/80290491
[2]https://blog.csdn.net/weixin_42350212/article/details/80768041
[3]https://www.cnblogs.com/lwlxqlccc/p/8618740.html
[4]https://blog.csdn.net/guomutian911/article/details/45771621
……还有很多很多很多很多,主要还是第一个地址正则表达式的参考

3.设计实现的具体

一个主类,类中有一个main方法,,五个处理函数,一个输出函数。没有太过复杂的结构,在主函数中依次调用获取名字、获取电话号码、获取地址的函数,最后调用输出函数。

String nameResolution(String peoplename) //获取名字
String phoneNumberResolution(String phoneNumber) //获取电话号码
String addressResolution(String address)  //获取一整串地址
ArrayList<String>  detailaArress1(String address) //难度1,五级地址
ArrayList<String>  detailAddress2(String address) //难度2,七级地址
Map<String, Object> getJson(String name,String phone,ArrayList<String> arrayList) //输出函数

4.独到之处(???相对于自己以前的水平来说):

(1)先用正则取出包括感叹号之前的字符串,再用substring函数按字符串长度减一切割掉最后的感叹号。

	String regex2="(!.+,)";
		Matcher n=Pattern.compile(regex2).matcher(peoplename);
		while(n.find())
			name=n.group();
		name=name.substring(1,name.length()-1);

(2)在获取一整串地址时,先用正则提取出逗号之后包括逗号的字符串,再执行获取手机的函数返回一串手机号码的字符串,最后用replaceAll()函数手机号码去掉

		String regex3="(,.+\\.)";
		String reg=phoneNumberResolution(address); //address和phonenumber本质都是line
		Matcher a=Pattern.compile(regex3).matcher(address);
		while(a.find())
			add=a.group();
		add = add.replaceAll(reg, "");
		add=add.substring(1,add.length()-1);

(3)用判断式子来解决当某个部分没有取得字符串时,输出的是“”而不是null

			province = m.group(1)== null?"":m.group(1);
			city = m.group(2)== null?"":m.group(2);
			county=m.group(3)== null?"":m.group(3);
			town=m.group(4)==null?"":m.group(4);
			village=m.group(5)==null?"":m.group(5);

(4)在解析地址的每个部分后,用arrayList动态数组的add函数来保存数据
(5)用string.equals(“str”)来判断字符串是否相等

5.遇到的问题:

1.通过正则匹配和字符串切割出来的代表难度系数的字符1、2、3还是字符串,在判断条件时不能使用来判断是否相等。要使用string.equals(“1”)这样函数来判断。因为是两边的完完全全是一致的,才返回true,否则返回false。equal是判断两个对象中的内容是否一致,所以第二个例子 我们使用equal进行判断,返回值为true 使用 ==判断则返回false。
2.采用上面那种方式会导致如果没有获取到某一段的地址,存储那个字符串的值是null,而题目要求我们,如果没有输出的话要输出“”。
原先的代码:

        String regex4="(?<province>[^省]+自治区|.*?省|.*?行政区)(?<city>[^市]+自治州|.*?地区|.*?行政单位|.+盟|市辖区|.*?市|.*?县)(?<county>[^县]+县|.+区|.+市|.+旗|.+海域|.+岛)?(?<town>[^区]+区|.+镇|.+街道)?(?<path>[^路]+路|.+街|.+巷)?(?<num>[^号]+号)?(?<village>.*)";
        Matcher m=Pattern.compile(regex4).matcher(address);
        String province=null,city=null,county=null,town=null,path=null,num=null,village=null;
        
		while(m.find())
		{
			province=m.group("province");
			city=m.group("city");
			county=m.group("county");
			town=m.group("town");
			path=m.group("path");
			num=m.group("num");
			village=m.group("village");
		}   
		

改了的代码:

        String regex4="(?<province>[^省]+自治区|.*?省|.*?行政区)(?<city>[^市]+自治州|.*?地区|.*?行政单位|.+盟|市辖区|.*?市|.*?县)(?<county>[^县]+县|.+区|.+市|.+旗|.+海域|.+岛)?(?<town>[^区]+区|.+镇|.+街道)?(?<path>[^路]+路|.+街|.+巷)?(?<num>[^号]+号)?(?<village>.*)";
        Matcher m=Pattern.compile(regex4).matcher(address);
        String province=null,city=null,county=null,town=null,path=null,num=null,village=null;
        
		while(m.find())
		{
			province = m.group(1)== null?"":m.group(1);
			city = m.group(2)== null?"":m.group(2);
			county=m.group(3)== null?"":m.group(3);
			town=m.group(4)==null?"":m.group(4);
			path=m.group(5)==null?"":m.group(5);
			num=m.group(6)==null?"":m.group(6);
			village=m.group(7)==null?"":m.group(7);
		} 

3.本来还打算考虑直辖市的情况,通过city的值,来给province赋值。但发现这仍然是缺少关键字中的缺少“省”关键字的情况。
4.本来并没有看到x!在测试数据的前面

四、计算模块接口部分的性能改进

记录在改进计算模块性能上所花费的时间已填在表里

改进的思路:可以试着不同功能放在不同的类中编写代码,实现真正的模块化.

性能分析图

程序中消耗最大的函数:地址与数据进行正则匹配的函数消耗最大

五、计算模块部分单元测试展示

项目部分单元测试代码

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.lang.String;

public class test {

	public static void main(String[] args)
	{
		String[] arr= {"福建省莆田市城厢区凤凰山街道学园路10号第十小区", //正常七级
						"福建省福州市闽侯县上街镇学府南路1号福建师范大学榕苑" , //正常七级,镇与街道是同一级
						"湖北省武汉市洪山区华中科技大学",       
						"福建省福州市闽侯县上街镇学园南路2号福州大学旗山校区",//正常七级
						"新疆维吾尔自治区乌鲁木齐市新市区温州商业街22号",   //自治区,缺4,7
						"上海市闵行区凯城路99号东城一号小区",   //直辖市,五级    null
						"福建省厦门市思明区湖滨北路61号厦门市人民政府",  //七级,缺4
						"香港特别行政区中西区香港中环雅宾利道香港动植物公园",  //特别行政区,道?
						"浙江省杭州市上城区解放路154号奎元馆",   //七级,缺4
						"湖北省恩施土家族苗族自治州恩施市施州大道34号",};  //自治州
		for(int i=0;i<arr.length;i++)
		{	
			Object[] array=detailAddress2(arr[i]).toArray(); //将list直接转为object数组
			for(int j=0;j<array.length;j++)
			{
				System.out.println(array[j]);
			}
			System.out.println("~~~~~~~~~~~~~~~~~");
		}

	}
	public static ArrayList<String>  detailAddress2(String address) //难度2,七级地址
	{
        String regex4="(?<province>[^省]+自治区|.*?省|.*?行政区)(?<city>[^市]+自治州|.*?地区|.*?行政单位|.+盟|市辖区|.*?市|.*?县)(?<county>[^县]+县|.{2,4}区|.+市|.+旗|.+海域|.+岛)?(?<town>.{2,4}区|.+镇|.+街道)?(?<path>[^路]+路|.+街|.+巷|.+道)?(?<num>[^号]+号)?(?<village>.*)";
        Matcher m=Pattern.compile(regex4).matcher(address);
        String province=null,city=null,county=null,town=null,path=null,num=null,village=null;
        
		while(m.find())
		{
			province = m.group(1)== null?"":m.group(1);
			city = m.group(2)== null?"":m.group(2);
			county=m.group(3)== null?"":m.group(3);
			town=m.group(4)==null?"":m.group(4);
			path=m.group(5)==null?"":m.group(5);
			num=m.group(6)==null?"":m.group(6);
			village=m.group(7)==null?"":m.group(7);
		}   
		ArrayList<String> arrayList = new ArrayList<String>();
		arrayList.add(province);
		arrayList.add(city);
		arrayList.add(county);
		arrayList.add(town);
		arrayList.add(path);
		arrayList.add(num);
		arrayList.add(village);
		return arrayList;
	}
}

运行结果:

福建省
莆田市
城厢区
凤凰山街道
学园路
10号
第十小区
~~~~~~~~~~~~~~~~~
福建省
福州市
闽侯县
上街镇
学府南路
1号
福建师范大学榕苑
~~~~~~~~~~~~~~~~~
湖北省
武汉市
洪山区



华中科技大学
~~~~~~~~~~~~~~~~~
福建省
福州市
闽侯县
上街镇
学园南路
2号
福州大学旗山校区
~~~~~~~~~~~~~~~~~
新疆维吾尔自治区
乌鲁木齐市
新市区

温州商业街
22号

~~~~~~~~~~~~~~~~~
null
null
null
null
null
null
null
~~~~~~~~~~~~~~~~~
福建省
厦门市
思明区

湖滨北路
61号
厦门市人民政府
~~~~~~~~~~~~~~~~~
null
null
null
null
null
null
null
~~~~~~~~~~~~~~~~~
浙江省
杭州市
上城区

解放路
154号
奎元馆
~~~~~~~~~~~~~~~~~
湖北省
恩施土家族苗族自治州
恩施市

施州大道
34号

~~~~~~~~~~~~~~~~~

测试的函数是 :ArrayList detailAddress2(String address)

构造测试数据的思路: 1.完整的地址和缺失部分街道、门牌号之类的地址都要有;
2.包含自治州、自治区、直辖市、特别行政区等特殊地址
3.还考虑到详细地址中可能会出现跟之前正则判断有关的关键字,譬如最后一部分详细地址是厦门市人民政府

单元测试得到的测试覆盖率截图:

六、计算模块部分异常处理说明。

1.在我编写代码的时候没有处理3!的部分,所以在Main函数中不会有输出,在单元测试的代码中不会自动补全。
样例 浙江省杭州市上城区解放路154号奎元馆
输出 浙江省 杭州市 上城区 解放路 154号 奎元馆
2.没有处理缺少关键字的部分,会导致直辖市还有关键字缺失的情况不能处理。
样例 上海市闵行区凯城路99号东城一号小区
输出 null null null null null null null
3.当详细地址中出现了校区、小区这样的地址会对前面区的判断产生影响。在单元测试中发现了该问题,然后修改了正则。
样例 福建省福州市闽侯县上街镇学园南路2号福州大学旗山校区
错误输出 福建省 福州市 闽侯县 上街镇 学园南路 2号 福州大学旗山校区
输出 福建省 福州市 闽侯县 上街镇学园南路2号福州大学旗山校区

七、PSP表格记录下你在程序的各个模块上实际花费的时间。

(在二、中)


  1. 0-9 ↩︎

posted @ 2019-09-29 09:56  songyue  阅读(230)  评论(2编辑  收藏  举报