作业总结2
相较于这轮的三次作业,比之前难了不止一点。这次的作业有了封装,正则表达式,以及一个复杂的点菜系统。
第四次PTA
这次的作业对我来说真的是惨不忍睹,这是我第一次pta没有及格(),这次作业的7-1是第一道较为复杂的实例,也是我这次滑铁卢的“罪魁祸首”,当时我信心满满的在截止前的那个晚上准备了4个多小时来写这题,幻想着通过这道题来让我及格,但是事实予以我痛击,我只写好了类和方法,主函数才动手没多少,直到第6次PTA才明白这不是几个小时能完成的任务。而其他几题是对算法的改进,查找使用API文档,使用JDK给出的方法来完成这些题。
1 import java.time.LocalDate; 2 import java.time.format.DateTimeFormatter; 3 import java.time.temporal.ChronoUnit; 4 import java.util.Scanner; 5 6 public class Main{ 7 public static void main(String[] args) { 8 Scanner in = new Scanner(System.in); 9 10 String strDate1=in.nextLine(); 11 String strDate2=in.nextLine(); 12 // LocalDate.parse()函数用于将字符串解析为LocalDate类型 13 // DateTimeFormatter是要解析的字符串模板,ISO_LOCAL_DATE相当于解析 yyyy-MM-dd 格式的字符串模板 14 // yyyy-MM-dd 在解析如 2023-3-28 时格式不匹配会报错 用yyyy-M-d 15 // DateTimeFormatter.ofPattern ofPattern("...")设置自定义的字符串模板 16 LocalDate dateParse1 = LocalDate.parse(strDate1,DateTimeFormatter.ofPattern("yyyy-M-d")); 17 LocalDate dateParse2 = LocalDate.parse(strDate2,DateTimeFormatter.ofPattern("yyyy-M-d")); 18 19 20 if( dateParse1.equals(dateParse2) ) { 21 System.out.println("第一个日期与第二个日期相同"); 22 System.out.println("两个日期间隔0天"); 23 System.out.println("两个日期间隔0周"); 24 } 25 else { 26 if( dateParse1.isAfter(dateParse2)) { 27 System.out.println("第一个日期比第二个日期更晚"); 28 //计算两天的差 29 int betweenDay = (int) ChronoUnit.DAYS.between(dateParse2, dateParse1); // 小一点的日期,大一点的日期,否则会出现负数 30 System.out.println("两个日期间隔"+betweenDay+"天"); 31 System.out.println("两个日期间隔"+betweenDay/7+"周"); 32 } 33 else { 34 System.out.println("第一个日期比第二个日期更早"); 35 int betweenDay = (int) ChronoUnit.DAYS.between(dateParse1, dateParse2); 36 System.out.println("两个日期间隔"+betweenDay+"天"); 37 System.out.println("两个日期间隔"+betweenDay/7+"周"); 38 } 39 } 40 } 41 }
比如这题使用了time包里的方法,通过LocalDate.parse()方法来将字符串转化为LocalDate类型,然后使用equals()和isAfter()方法来比较两个LocalDate类型成员的大小,再使用
int betweenDay = (int) ChronoUnit.DAYS.between(dateParse2, dateParse1);计算他们之间的天数。
第五次PTA
这次作业前四题练习了正则表达式,让我们对于正则表达式的规则有了一定的了解。PS:虽然每次写正则时旁边都是放着正则的规则就是了(小声)。而后两题则是对于上次作业的日期类设计的该版。用不同的类关系重新写这道题。
第一题
用这种类对于年的属性的调用极度困难,要多次“套娃”DateUtil调用Day再调用Month再调用Year最后才能获得Year的属性。
第二题
相比与前一题这题对于属性的获取就没有那么困难了,但是他的Year,Month,Day这三个类的耦合低,所以对于判断日期是否合法变得稍微麻烦一些。
但总的来说这两题和上次的没什么区别,大部分内容都是从上次题目里Ctrl cv过来的
第六次PTA
这次的作业可以说是重中之重了,可谓是惨不忍睹,一半多的同学没有及格。
还是点菜程序,我称之为点菜程序2.0版本,相较于上次,他提出了许多新的要求。老师也很慷慨的告诉了我们这题的大概难道和所需设计。
首先分析这题,我们先写好类。
类之间的关系有点复杂,但我们可以按提示一点一点来。
Dish {
String name;//菜品名称
int unit_price; //单价
int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) }
菜谱类:对应菜谱,包含饭店提供的所有菜的信息。
Menu {
Dish[] dishs ;//菜品数组,保存所有菜品信息
Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。
Dish addDish(String dishName,int unit_price)//添加一道菜品信息
}
点菜记录类:保存订单上的一道菜品记录
Record {
int orderNum;//序号
Dish d;//菜品\\
int portion;//份额(1/2/3代表小/中/大份)
int getPrice()//计价,计算本条记录的价格
}
订单类:保存用户点的所有菜的信息。
Order {
Record[] records;//保存订单上每一道的记录
int getTotalPrice()//计算订单的总价
Record addARecord(int orderNum,String dishName,int portion,int num)//添加一条菜品信息到订单中。
delARecordByOrderNum(int orderNum)//根据序号删除一条记录
findRecordByNum(int orderNum)//根据序号查找一条记录
}
将这些写好后我们先分析它的输入情况
1* 麻婆豆腐 12
2* 油淋生菜 9 T
3* table 1 2022/12/5 15/03/02
4* 3 麻辣鸡丝 1 2
5* 7 delete
6* 1 4 麻婆豆腐 1 1
7* end
写出他们所对应的正则表达式。这样对于语句的判断会方便很多。然后我们分析它的输入语句,让我们的程序能够读懂一个正确输入的程序。你不可能写一遍就能将它的所有要求都做到。在哪一段插入一个判断,是要你在写的过程中添加的。
一、 对于菜单的补充
关于菜单先简单写好对于价格的规定后有了一个较为棘手的问题,什么时候结束?
1 //建立菜单 2 while(true) { 3 // 麻婆豆腐 12 4 // 油淋生菜 9 T 5 if(strLine.matches(regexDishes)) { 6 arrStr = strLine.split("[\\s]"); 7 int price = Integer.parseInt(arrStr[1]); 8 if(price > 300) { 9 System.out.println(arrStr[0]+" price out of range "+price); 10 } 11 else { 12 if(arrStr.length == 2) { 13 menu.addDish(arrStr[0], price,false); 14 } 15 if(arrStr.length == 3) { 16 menu.addDish(arrStr[0], price,true); 17 } 18 } 19 strLine = in.nextLine(); 20 } 21 else { 22 arrStr = strLine.split("[\\s]"); 23 if(arrStr[0].matches("table") || strLine.matches(regexErrTable)) { 24 break; 25 } 26 else { 27 System.out.println("wrong format"); 28 strLine = in.nextLine(); 29 } 30 } 31 }
我们可以很自然的看到在8,21行是一个很自然的if-else语句if进入对于菜单的建立else则又有两个分支:是否跳出菜单循环?是否是错误的菜单?而跳出循环时最开始的是遇到桌号信息就跳过,但这个带来了一个问题--如果桌号信息是错误的那么就陷入死循环了所以我们需要一个能读错误信号的正则表达式,23行油然而生。
二、桌号信息错误
桌号信息错误有好几种。
table正确,后面错误 。
1 discount = timeAndDiscount(strLine); 2 3 if(discount == -1) { 4 System.out.println("not a valid time period"); 5 } 6 if(discount == 0) { 7 System.out.println( arrStr[1] + " date error"); 8 } 9 if(discount == -2) { 10 System.out.println("table " + arrStr[1] + " out of opening hours"); 11 } 12 strLine = in.nextLine(); 13 if(discount == -1 || discount == 0 ||discount == -2) { 14 while(!strLine.matches(regexTable)) { 15 if(strLine.matches(regexEND)) { 16 discount = 255; 17 break; 18 }//读到了结束标志 19 strLine = in.nextLine(); 20 }//对应记录的格式或者数据不符合桌号的要求,那一桌下面定义的所有信息无论正确或错误均忽略,不做处理 21 }
这里我通过discount的返回值来执行相应的操作,discount初始值为0,返回值--折扣, -1 "not a valid time period" 0" date error" -2""table " + t.tableNum + " out of opening hours"
table错误则忽略。
三、考虑多个桌子
原先我使用的是HashMap,Key对应桌号,Value对应桌子的点菜记录。但这次要稍加修改,Map不允许有相同的Key,所以我们可以将Key表示为桌子的输入顺序,修改Order类。
1 class Order { 2 //初始大小为1,records[i],i 为订单记录信号 3 Record[] records = new Record[1];//保存订单上每一道的记录 4 int tableNum; 5 int time ; //周末单位秒,1-5.中午6,1-5.晚上8 6 }
用int类型表示时间6和8是工作日的中文和晚上,周末时间则用改时间对应的秒数表示。而周末最早的时间也与8相差超过3600,不会被影响到。
四、增加零零散散的要求
这些要求不会大幅度更改代码流程,所以可以归为一类,比如说份额,份数格式错误等。
总的来说:这次作业是一次不小的挑战,考察了对我们的理解分析问题的能力。同时也让我对于正则表达式在代码中的运用有了更加深刻的理解。