第一次个人编程作业
第一次个人编程作业
一、仓库地址
二、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
构造测试数据的思路: 1.完整的地址和缺失部分街道、门牌号之类的地址都要有;
2.包含自治州、自治区、直辖市、特别行政区等特殊地址
3.还考虑到详细地址中可能会出现跟之前正则判断有关的关键字,譬如最后一部分详细地址是厦门市人民政府
单元测试得到的测试覆盖率截图:
六、计算模块部分异常处理说明。
1.在我编写代码的时候没有处理3!的部分,所以在Main函数中不会有输出,在单元测试的代码中不会自动补全。
样例 浙江省杭州市上城区解放路154号奎元馆
输出 浙江省 杭州市 上城区 解放路 154号 奎元馆
2.没有处理缺少关键字的部分,会导致直辖市还有关键字缺失的情况不能处理。
样例 上海市闵行区凯城路99号东城一号小区
输出 null null null null null null null
3.当详细地址中出现了校区、小区这样的地址会对前面区的判断产生影响。在单元测试中发现了该问题,然后修改了正则。
样例 福建省福州市闽侯县上街镇学园南路2号福州大学旗山校区
错误输出 福建省 福州市 闽侯县 上街镇 学园南路 2号 福州大学旗山校区
输出 福建省 福州市 闽侯县 上街镇学园南路2号福州大学旗山校区
七、PSP表格记录下你在程序的各个模块上实际花费的时间。
(在二、中)
0-9 ↩︎