前言
对10~16周学习的内容,由本次博客来进行一个总结。
1.这几周主要是电信收费系列题目,考察我们对于正则表达式的掌握于运用。
2.对于课程来说,主要讲解了javafx和集合框架,javafx相对于集合框架来说比较简单。
3.集合框架的内容虽然不会考,但是其实也会有所涉及,就像ArrayList和HashSet其实都是经常使用的。
第五次作业——题目集05 7-1和7-2
难度:偏大
整体思路分析
本题的难度偏大,我在拿到这个题目之后,首先想到的是对输入五个点的是否冗杂的判断,只有判断了这个出来之后才能进行后续是五边形,四边形亦或是三角形的计算。
这道题我一直只使用了一个点类,我感觉这是十分限制我这道题后续的一个点。7-1和7-2两题的类图我都是这个,因为我在写7-2时,并没有将每个选项中的功能写成方法。
度量分析
圈复杂度54,可以看出来这题的难度很大,代码质量很差。
核心代码分析
下面是对点是否冗杂的判断,先看有没有点重复,将不重复的点加入ArrayList中,然后再对其中的点进行是否在一条边上的判断。
public static ArrayList<Dot> checkDot(Dot dot[]) { ArrayList<Dot> dots=new ArrayList<Dot>(); for(int i=0;i<dot.length;i++) { if(dots.size()==0) { dots.add(dot[i]); } for(int j=0;j<dots.size();j++) { if(isSame(dots.get(j),dot[i])) break; if(j==dots.size()-1) { dots.add(dot[i]); } } } for(int i=0;i<dots.size();i++) { if(dots.size()<3) break; else { if(i-1>=0&&i+1<dots.size()) { if(isLine(dots.get(i-1),dots.get(i),dots.get(i+1))) dots.remove(i); if(isLine(dots.get(i-1),dots.get(i),dots.get(i+1))) dots.remove(i); } } } return dots;
采坑分析
这题最大的坑就是在算交点的时候,会存在斜率不存在的情况,而这个时候用斜率去计算,就算是考虑了斜率不存在的情况,也会存在计算错误,在网上学习过之后,我采用了向量法对其进行计算,但到现在我依旧不知道为什么不能够用斜率进行计算。
改进建议
1.这题写字符串格式是否合法的那个方法时,总会有测试点过不去,较第一题而言,这一题多了对前面选项已经冒号的判断,但我还发现还多了对连续两个空格或者逗号的测试点。
2.这题的圈复杂度高达54,写的时候基本就是想到什么非法格式,就强行写一个语句给他加进去,并没有考虑到如何对代码进行优化,导致代码总体的复杂度很高,而且本题虽然是面向对象,但依旧采用的是赋值的手段,没有使用构造方法,这应该也是增大复杂度的一个点。所以在子类构造方法中,一定要注意重写的时候是否是无参的,若是有参的构造函数,应该加上super方法。
第六次作业——题目集06 7-1
题目集06 7-1开始电信收费系列题目,主要是对正则表达式的考察。
整体思路介绍
题目集06 7-1已经被大大的降低了难度,题目已经给出了各个板块的类图。
这三张类图已经将整个题目的大体框架给出来了,只需要我们在对其进行代码实现,然后实现相应的功能即可。
对于功能来说,题目集06 7-1主要功能是正则表达式的匹配,题目需要我们匹配正确的输入格式,给用户开户并对接下输入的通话记录进行正则表达式的匹配。其中的主要类就是CallRecord和CallChargeRule,对于CallRecord来说,需要在构造函数时,就传入相应的startTime,endTime,callingNumberAreaCode,answerNumberAreaCode,number1,number2这六个参数。其中需要使用到一个SimpleDateFormat类对字符串形式的时间进行转化,使其变成计算机可以识别的Date类型。
度量分析
从Kiviat Graph可以看出来自己写的代码虽然现在全复杂度变低了但是各种数据依旧不是在优秀的范围之中,说明代码依旧是比较垃圾的代码。
核心代码分析
我认为这是电信收费题目中最重要的地方,对于输入的字符串进行正则表达式的匹配,之后才能进行之后的操作。其中regex1是匹配u-0791+7~8个数字+空格+0这样的字符串,而regex2是对类似“t-079186300001 058686330022 2022.1.3 10:00:25 2022.1.3 10:05:25”这样的字符串进行匹配。
在匹配到和regex1相同类型的字符串后进行开户,注意不能重复开户,一下代码就是这一步:
if (matcher1.find()&&flag==0) { String number="0791"+matcher1.group(1); String choice=matcher1.group(2); if(choice.equals("0")) { if(users.size()>=1) { for(int i=0;i< users.size();i++) { if(users.get(i).getNumber().equals(number)) { flag1=false; } } if(flag1) { User user=new User(number); ChargeMode landlinePhoneCharging=new LandlinePhoneCharging(); user.setChargeMode(landlinePhoneCharging); users.add(user); } } else { User user=new User(number); ChargeMode landlinePhoneCharging=new LandlinePhoneCharging(); user.setChargeMode(landlinePhoneCharging); users.add(user); } } }
而对于通话记录的记录,在匹配到字符串之后,用group方法将接听电话和拨打电话分别提取出来,再使用一次正则表达式提取出接听电话的区号,这里要注意需要使用SimpleDateFormat类进行相应的格式转化,将字符串类型的时间转化为Date类型,然后判断开始时间是否小于结束时间,再进行记录的添加:
else if(matcher2.find()&&users.size()>=1) { flag=1; String number1=matcher2.group(1); String number2=matcher2.group(2); String callingNumberAreaCode=number1.substring(0,4); String answerNumberAreaCode=number2.substring(0,4); String regex3="(079[2-9])|(0701)"; Pattern pattern3=Pattern.compile(regex3); Matcher matcher3=pattern3.matcher(answerNumberAreaCode); SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); String str[]=tmp.split(" "); String time1 = str[2]+" "+str[3]; String time2=str[4]+" "+str[5]; Date startTime =simpleDateFormat.parse(time1); Date endTime=simpleDateFormat.parse(time2); if(endTime.getTime()-startTime.getTime()>0) { for(int i=0;i< users.size();i++) { UserRecords userRecords=users.get(i).getUseRecords(); CallRecord callRecord=new CallRecord(startTime,endTime,callingNumberAreaCode,answerNumberAreaCode,number1,number2); if(users.get(i).getNumber().equals(number1)) { if(answerNumberAreaCode.equals("0791")) { userRecords.addCallingInCityRecords(callRecord); } else if(matcher3.find()) { userRecords.addCallingInProvinceRecords(callRecord); } else { userRecords.addCallingInLandRecords(callRecord); } } } } }
采坑心得
这道题的坑很多,让我最为痛恨的就是在正则表达式匹配时,对于时间的匹配会出现2022.13.61 28:72:65这种情况,而pta有个测试点是单用户综合计算错误,我一开始正则表达式并没有考虑到这样的输入格式,所以这个测试点一直过不去,但因为说是计算错误所以我一直没有去想是不是正则表达式的问题,而是一直对计算通话时间和计算话费的方法进行更改,但还是一直通过不了测试点,最终我放弃改计算的想法,将正则表达式改对才发现是正则表达式的问题。
还有一个坑就是在使用group()方法时,进行识别的时候是按照括号来的,所以在匹配时就应该用对应的括号来分好区域,最后使用group时,会出现匹配到单个的情况,这时候只需要再往后增加group的位数就可发现,group还会有子group。
改进建议
可以利用一些方法减少代码的重复,因为在后续还会有这个系列的题目发布,需要代码具有可拓展性和较高的可修改性。
第七次作业——题目集07 7-1
难度:中等
整体思路分析
1.这次题目对于上次增加了手机用户,需要我们对手机用户进行开户并记录通话记录。
2.手机通话计费方式不同,存在接电话要钱的情况。
3.较题目集06 7-1的基础上需要增添手机的计费模式和规则。
4.考察对于Comparable接口的使用,需要实现方法对User进行排序。
度量分析
从度量分析中其实可以看出来在使用了方法记录通话记录和计算时间后相比于题目集06 7-1本题的平均复杂度已经变小了,但整体的代码依旧可用性不高。
核心代码分析
这六个正则分别对应座机开户,座机打座机,手机开户,座机打手机,手机打手机,手机打座机的情况,无非就是在之前的基础上加上类似的代码。但需要注意的是,这一次我在识别的时候就将区号和号码分割开了。之后只需要使用group方法就能分别提取出区号和号码。
采坑分析
在写这个题目的时候,出现了我写题目集06 7-1没有出现过的情况。在题目集96 7-1中对于区号我是再使用一遍正则表达式来进行提取。其实这样没错,但在区别区号是否在省内的时候,我是使用了matcher.find()这个方法来进行识别,即若匹配到(079[2-9])|(0701)中的一个就为true,但经过调试我发现,这个方法只会进行一次,在之后就变成了false,在之后我就修改了我的代码,先将其转化为整形数,再进行比较。
改进建议
在正则表达式上可以更加的简略一些,可以将regex1和regex4写成一个正则表达式,同理匹配通话记录的也是这样,这样可以大大的减少代码的复杂性。在另一方面,其实可以不需要按照题目所给类图这样来进行代码编写,因为我发现在通过所有测试点之后依旧有一些方法是从来没有使用过的。这会显的代码十分的复杂,提高了代码量,应该想办法改变这一过程。
第八次作业——题目集08 7-1
整体思路分析
难度:简单
1.题目要求我们在对手机用户进行短信的计费编写代码。
2.本题只要在写前面两题时,学会正则表达式就能很容易的解决。
3.之前两个题目集中的功能并不需要在本次题目中实现,只需要进行手机短信的计算。
度量分析
核心代码分析
本题最主要就是对于数字,字符,空格,英文逗号,英文句号组成的短信进行正则表达式的匹配。
改进建议
后面经过和同学讨论发现,这类题目不按照类图写其实可以大大的减少代码量。
总结
经过了10~16周的学习,我学习到了:
1.对于面向对象程序设计,尽可能的从对象的角度出发来设计自己的程序,只有这样才能减少代码的复杂度。
2.能写成方法的地方一定要写成方法。
3.多使用继承和多态,能够提高代码的复用性。
4.构造方法在子类中的重写和与父类的关系。
5.对于集合框架,有了一个较为清晰的了解,较为清晰的知道了什么是ArrayList,什么是HashSet,什么是HashMap,也能够在适当的地方进行使用。
6.在写程序时,要尽最大的可能减少类于类之间的耦合,对于面向对象程序设计来说,类与类之间的耦合越低越好。
7.泛型类之间也能够进行继承,但只能有一个类,且这个类必须在第一位,类是对象的模板,泛型类是类的模板。当我们需要不知道某一具体类型时,就可以用泛型类。
经过了10~16周的学习,需要进一步研究的地方:
1.如何降低类与类之间耦合。
2.在接触到一个题目时,如何先有一个大体的思路。
3.对于代码实现的能力还有待欠缺。
4.数学思维能力明显不足,需要进一步提高。
标签:题目,第三次,匹配,正则表达式,代码,group,blog,java,String From: https://www.cnblogs.com/2202-w/p/16972489.html