第三次大作业blog
前言:
这里是第三次大作业的blog(包含PTA作业6~8),与前两次相同,这次也是将一道大题分成了三次作业。首先题量并不算大,而且在第一次的基础上进行增加/修改可以减少第二、第三次作业的题量。相较于多边形系列题目,这次电信计费系列的难度稍稍有所降低(毕竟少了很多需要自己想的运算)。这次涉及到的知识点还是类、成员变量、方法和动态数组arraylist的各种操作。如何利用合理的操作将题目给出的类和方法串联起来进行使用是本题最大的需要处理的问题。编程方面常识性错误出现的情况这次没有出现了(比如说,忘记创建对象什么的,毕竟都写了那么久代码)但是在写完后一运行哎,没有答案出来。之后还是调试了很久,将样例都运行成功后再考虑剩下的情况,虽然最后也没能拿到满分...但是也是一次很好的学习体验,还需更加努力。
设计与分析:
一.电信计费系列1-座机计费
1.题目要求:
实现一个简单的电信计费程序:
假设南昌市电信分公司针对市内座机用户采用的计费方式:
月租20元,接电话免费,市内拨打电话0.1元/分钟,省内长途0.3元/分钟,国内长途拨打0.6元/分钟。不足一分钟按一分钟计。
南昌市的区号:0791,江西省内各地市区号包括:0790~0799以及0701。
输入格式:
输入信息包括两种类型
1、逐行输入南昌市用户开户的信息,每行一个用户,
格式:u-号码 计费类型 (计费类型包括:0-座机 1-手机实时计费 2-手机A套餐)
例如:u-079186300001 0
座机号码除区号外由是7-8位数字组成。
本题只考虑计费类型0-座机计费,电信系列2、3题会逐步增加计费类型。
2、逐行输入本月某些用户的通讯信息,通讯信息格式:
座机呼叫座机:t-主叫号码 接听号码 起始时间 结束时间
t-079186330022 058686330022 2022.1.3 10:00:25 2022.1.3 10:05:11
以上四项内容之间以一个英文空格分隔,
时间必须符合"yyyy.MM.dd HH:mm:ss"格式。提示:使用SimpleDateFormat类。
以上两类信息,先输入所有开户信息,再输入所有通讯信息,最后一行以“end”结束。
注意:
本题非法输入只做格式非法的判断,不做内容是否合理的判断(时间除外,否则无法计算),比如:
1、输入的所有通讯信息均认为是同一个月的通讯信息,不做日期是否在同一个月还是多个月的判定,直接将通讯费用累加,因此月租只计算一次。
2、记录中如果同一电话号码的多条通话记录时间出现重合,这种情况也不做判断,直接 计算每条记录的费用并累加。
3、用户区号不为南昌市的区号也作为正常用户处理。
输出格式:
根据输入的详细通讯信息,计算所有已开户的用户的当月费用(精确到小数点后2位,
单位元)。假设每个用户初始余额是100元。
每条通讯信息单独计费后累加,不是将所有时间累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略。
2.题目分析
这题作为电信计费题目系列的第一题,主要是向我们展示了非常复杂非常多的类和方法(bushi)同时也给了我们解题思路:首先将用户类、计费规则类、记录类进行完善,之后再对输入数据进行处理,最后调用各个方法就好了。
三个类的处理涉及到最多的就是动态数组ArrayList的操作,重点用于记录用户信息和通话记录信息,后者会在计费操作中进行调用以达成程序目标。通话记录类也根据通话双方的地址不同进行了区分。除了有点绕容易搞晕其他的难度不算大。
而在将三个类处理好后就是对输入数据进行分析和存储,还是用我们的正则表达式对输入数据进行判断,实现将不符合规定格式的输入无视,然后再将输入用户信息和通话记录信息的输入分别处理后存储。针对通话记录这一块,我是在判断阶段就将其通话地址判断后就存入相应的通话记录类中,而不是在后续操作中在进行区分。当读取完所有输入后,再对存在的用户的通话记录进行查询并扣除掉相应的话费,最后给出相应的余额。
3.源码:
package zmyyyyyyyyyy; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Scanner; import java.math.BigDecimal; public class Main { public static void main(String[] args) { String u = "u\\-\\d{11,12}\\s0"; String num = "\\d{11,12}"; String t = "t-(\\d{10,12})\\s(\\d{10,12})\\s(\\d{4}.([1-9]{1}|1[0-2]).([1-9]{1}|1[0-9]|2[0-9]|3[0-1])\\s(0[0-9]|1[0-9]|2[0-3]):([0-5]{1}[0-9]):([0-5]{1}[0-9]))\\s([0-9]{4}.([1-9]{1}|1[0-2]).([1-9]{1}|1[0-9]|2[0-9]|3[0-1])\\s(0[0-9]|1[0-9]|2[0-3]):([0-5]{1}[0-9]):([0-5]{1}[0-9]))"; Scanner sc = new Scanner(System.in); User [] users = new User[100]; String s; int y = 0; do { s = sc.nextLine(); if (s.charAt(0)=='u'){//2~13 if (s.matches(u)) { if (y==0) { users[y] = new User(); String number = ""; for (int z = 2 ; z < 15 ; z ++){ if (s.charAt(z)!=' ') number+=s.charAt(z); else break; } if (number.length()==11||number.length()==12) { users[y].setNumber(number); y++; } } else { int mark = 1; String number = ""; for (int z = 2 ; z < 15 ; z ++){ if (s.charAt(z)!=' ') number+=s.charAt(z); else break; } for (int z = 0 ; z < y ; z ++){ if (number.equals(users[z].number)){ mark = 0; break; } } if (mark==1){ users[y] = new User(); users[y].setNumber(number); y++; } } } } else { if (s.matches(t)) { long time; Date date = null; Date date1 = null; int z = 2; int j; int d1,d2; CallRecord callRecord = new CallRecord(); String number1 = "", number2 = ""; String da1 = ""; for (z = 2; z < 14; z++) { if (s.charAt(z) != ' ') number1 += s.charAt(z); else break; } for ( j = z + 1; j < 28; j++) { if (s.charAt(j) != ' ') number2 += s.charAt(j); else break; } for (d1 = j +1 ; d1<48 ; d1++){ if (s.charAt(d1)!=' '||(s.charAt(d1)==' '&&s.charAt(d1+3)==':')) da1+=s.charAt(d1); else break; } callRecord.callingNumber = number1; callRecord.answerNumber = number2; if (callRecord.callingNumber.matches(num) && callRecord.answerNumber.matches(num)) { callRecord.callingAddressCode = callRecord.callingNumber.substring(0, 4); callRecord.answerAddressCode = callRecord.answerNumber.substring(0, 4); try { SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); String sDate = da1; String sDate2 = s.substring(d1+1,s.length()); date = simpleDateFormat1.parse(sDate); date1 = simpleDateFormat1.parse(sDate2); } catch (ParseException e) { e.printStackTrace(); } callRecord.startTime = date; callRecord.endTime = date1; if (callRecord.endTime.getTime() > callRecord.startTime.getTime()) { for (int m = 0; m < y; m++) { if (callRecord.callingNumber.matches(users[m].number)) { if (callRecord.callingAddressCode.matches("0791") && callRecord.answerAddressCode.matches("0791")) { users[m].userRecords.callingCityRecord.add(callRecord); } else if ((callRecord.callingAddressCode.matches("0701") || callRecord.callingNumber.substring(0, 3).matches("079")) && ((callRecord.answerAddressCode.matches("0701") || callRecord.answerNumber.substring(0, 3).matches("079")))) { users[m].userRecords.callingProvinceRecord.add(callRecord); } else { users[m].userRecords.callingLandRecord.add(callRecord); } } } } } } } } while (!s.equals("end")); for (int zmy = 0 ; zmy < y-1 ; zmy++){ for (int zsh = 1 ; zsh < y ; zsh++) { User user = new User(); if (Long.parseLong(users[zmy].number) > Long.parseLong(users[zsh].number)) { user = users[zmy]; users[zmy] = users[zsh]; users[zsh] = user; } } } for (int zsh = 0 ; zsh < y ; zsh ++){ users[zsh].CalBalance(); System.out.println(users[zsh].number+" "+change(users[zsh].CalCost())+" "+change(users[zsh].balance)); } } public static double change(double d) {//转化为两位小数 double d1; BigDecimal big = new BigDecimal(d); d1 = big.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); return d1; } public static double up(double d){ double d1; BigDecimal bigDecimal = new BigDecimal(d); d1 = bigDecimal.setScale(0,BigDecimal.ROUND_UP).doubleValue(); return d1; } } //图1中User是用户类,包括属性: //userRecords (用户记录)、balance(余额)、chargeMode(计费方式)、number(号码)。 // //ChargeMode是计费方式的抽象类: //chargeRules是计费方式所包含的各种计费规则的集合,ChargeRule类的定义见图3。 //getMonthlyRent()方法用于返回月租(monthlyRent)。 // //UserRecords是用户记录类,保存用户各种通话、短信的记录, //各种计费规则将使用其中的部分或者全部记录。 //其属性从上到下依次是: //市内拨打电话、省内(不含市内)拨打电话、省外拨打电话 //市内接听电话、省内(不含市内)接听电话、省外接听电话的记录 //以及发送短信、接收短信的记录。 class User{ UserRecords userRecords = new UserRecords(); double balance = 100; ChargeMode chargeMode; String number; public double CalBalance(){ double reBalance; LandLinePhoneCharging landLinePhoneCharging = new LandLinePhoneCharging(); reBalance = this.balance - (this.CalCost() + landLinePhoneCharging.getMonthlyRent()); this.balance = reBalance; return balance; } public double CalCost(){ double calCost; LandLinePhoneCharging landLinePhoneCharging = new LandLinePhoneCharging(); calCost = landLinePhoneCharging.calCost(userRecords); return calCost; } public UserRecords getUserRecords() { return userRecords; } public void setUserRecords(UserRecords userRecords) { this.userRecords = userRecords; } public double getBalance() { return balance; } public ChargeMode getChargeMode() { return chargeMode; } public void setChargeMode(ChargeMode chargeMode) { this.chargeMode = chargeMode; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } } abstract class ChargeMode{ ArrayList<ChargeRule> chargeRules = new ArrayList<>(); public ArrayList<ChargeRule> getChargeRules() { return chargeRules; } public void setChargeRules(ArrayList<ChargeRule> chargeRules) { this.chargeRules = chargeRules; } public abstract double calCost(UserRecords userRecords); public abstract double getMonthlyRent(); } class LandLinePhoneCharging extends ChargeMode{ public double monthlyRent = 20; public double calCost(UserRecords userRecords){ double calCost; LandPhoneInCityRule city = new LandPhoneInCityRule(); LandPhoneInProvinceRule province = new LandPhoneInProvinceRule(); LandPhoneInLandRule land = new LandPhoneInLandRule(); calCost = city.calCost(userRecords.callingCityRecord)+ province.calCost(userRecords.callingProvinceRecord)+land.calCost(userRecords.callingLandRecord); return calCost; } public double getMonthlyRent() { return monthlyRent; } } class UserRecords{ ArrayList<CallRecord> callingCityRecord = new ArrayList<>(); ArrayList<CallRecord> callingProvinceRecord = new ArrayList<>(); ArrayList<CallRecord> callingLandRecord = new ArrayList<>(); ArrayList<CallRecord> answerCityRecord = new ArrayList<>(); ArrayList<CallRecord> answerProvinceRecord = new ArrayList<>(); ArrayList<CallRecord> answerLandRecord = new ArrayList<>(); public ArrayList<CallRecord> getCallingCityRecord() { return callingCityRecord; } public ArrayList<CallRecord> getCallingProvinceRecord() { return callingProvinceRecord; } public ArrayList<CallRecord> getCallingLandRecord() { return callingLandRecord; } public ArrayList<CallRecord> getAnswerCityRecord() { return answerCityRecord; } public ArrayList<CallRecord> getAnswerProvinceRecord() { return answerProvinceRecord; } public ArrayList<CallRecord> getAnswerLandRecord() { return answerLandRecord; } public void addCallingCityRecord(CallRecord callRecord){ this.callingCityRecord.add(callRecord); } } //CommunicationRecord是抽象的通讯记录类: //包含callingNumber拨打号码、answerNumber接听号码两个属性。 //CallRecord(通话记录)、MessageRecord(短信记录)是它的子类。 abstract class CommunicationRecord{ public String callingNumber; public String answerNumber; public String getCallingNumber() { return callingNumber; } public void setCallingNumber(String callingNumber) { this.callingNumber = callingNumber; } public String getAnswerNumber() { return answerNumber; } public void setAnswerNumber(String answerNumber) { this.answerNumber = answerNumber; } } class CallRecord extends CommunicationRecord{ public Date startTime; public Date endTime; public String callingAddressCode; public String answerAddressCode; public Date getStartTime() { return startTime; } public void setStartTime(Date startTime) { this.startTime = startTime; } public Date getEndTime() { return endTime; } public void setEndTime(Date endTime) { this.endTime = endTime; } public String getCallingAddressCode() { return callingAddressCode; } public void setCallingAddressCode(String callingAddressCode) { this.callingAddressCode = callingAddressCode; } public String getAnswerAddressCode() { return answerAddressCode; } public void setAnswerAddressCode(String answerAddressCode) { this.answerAddressCode = answerAddressCode; } } //class MessageRecord extends CommunicationRecord{ // public String message; // // public String getMessage() { // return message; // } // // public void setMessage(String message) { // this.message = message; // } //} //图3是计费规则的相关类,这些类的核心方法是: //calCost(ArrayList<CallRecord> callRecords)。 //该方法针根据输入参数callRecords中的所有记录计算某用户的某一项费用;如市话费。 //输入参数callRecords的约束条件:必须是某一个用户的符合计费规则要求的所有记录。 // //LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是 //座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。 //(提示:可以从UserRecords类中获取各种类型的callRecords)。 abstract class ChargeRule{ } abstract class CallChargeRule extends ChargeRule{ public abstract double calCost(ArrayList<CallRecord> callRecords); } class LandPhoneInCityRule extends CallChargeRule{//市内 public double calCost(ArrayList<CallRecord> callRecords){ double money = 0; for (int z = 0 ; z < callRecords.size() ; z++) money += 0.1*Main.up(((callRecords.get(z).endTime.getTime()-callRecords.get(z).startTime.getTime())/6)*0.0001); return money; } } class LandPhoneInProvinceRule extends CallChargeRule{//省内 public double calCost(ArrayList<CallRecord> callRecords){ double money = 0; for (int z = 0 ; z < callRecords.size() ; z++) money += 0.3*Main.up(((callRecords.get(z).endTime.getTime()-callRecords.get(z).startTime.getTime())/6)*0.0001); return money; } } class LandPhoneInLandRule extends CallChargeRule{//国内/省外 public double calCost(ArrayList<CallRecord> callRecords){ double money = 0; for (int z = 0 ; z < callRecords.size() ; z++){ money += 0.6*Main.up(((callRecords.get(z).endTime.getTime()-callRecords.get(z).startTime.getTime())/6)*0.0001); } return money; } }
可以看到代码基本就是按照题目给出的类及方法推荐编写的
4.类图及复杂度分析:


类图基本就是按照题目推荐构成的,包含了各项可能会用到的类和相应的方法,而从复杂度可以看出平均深度和最大复杂度都明显超出了推荐值,虽然代码最后还是能正常运行,但这也是还需要更改的地方。
二.电信计费系列2-手机+座机计费
1.题目要求
实现南昌市电信分公司的计费程序,假设该公司针对手机和座机用户分别采取了两种计费方案,分别如下:
1、针对市内座机用户采用的计费方式(与电信计费系列1内容相同):
月租20元,接电话免费,市内拨打电话0.1元/分钟,省内长途0.3元/分钟,国内长途拨打0.6元/分钟。不足一分钟按一分钟计。
假设本市的区号:0791,江西省内各地市区号包括:0790~0799以及0701。
2、针对手机用户采用实时计费方式:
月租15元,市内省内接电话均免费,市内拨打市内电话0.1元/分钟,市内拨打省内电话0.2元/分钟,市内拨打省外电话0.3元/分钟,省内漫游打电话0.3元/分钟,省外漫游接听0.3元/分钟,省外漫游拨打0.6元/分钟;
注:被叫电话属于市内、省内还是国内由被叫电话的接听地点区号决定,比如以下案例中,南昌市手机用户13307912264在区号为020的广州接听了电话,主叫号码应被计算为拨打了一个省外长途,同时,手机用户13307912264也要被计算省外接听漫游费:
u-13307912264 1
t-079186330022 13307912264 020 2022.1.3 10:00:25 2022.1.3 10:05:11
输入:
输入信息包括两种类型
1、逐行输入南昌市用户开户的信息,每行一个用户,含手机和座机用户
格式:u-号码 计费类型 (计费类型包括:0-座机 1-手机实时计费 2-手机A套餐)
例如:u-079186300001 0
座机号码由区号和电话号码拼接而成,电话号码包含7-8位数字,区号最高位是0。
手机号码由11位数字构成,最高位是1。
本题在电信计费系列1基础上增加类型1-手机实时计费。
手机设置0或者座机设置成1,此种错误可不做判断。
2、逐行输入本月某些用户的通讯信息,通讯信息格式:
座机呼叫座机:t-主叫号码 接听号码 起始时间 结束时间
t-079186330022 058686330022 2022.1.3 10:00:25 2022.1.3 10:05:11
以上四项内容之间以一个英文空格分隔,
时间必须符合"yyyy.MM.dd HH:mm:ss"格式。提示:使用SimpleDateFormat类。
输入格式增加手机接打电话以及收发短信的格式,手机接打电话的信息除了号码之外需要额外记录拨打/接听的地点的区号,比如:
座机打手机:
t-主叫号码 接听号码 接听地点区号 起始时间 结束时间
t-079186330022 13305862264 020 2022.1.3 10:00:25 2022.1.3 10:05:11
手机互打:
t-主叫号码 拨号地点 接听号码 接听地点区号 起始时间 结束时间
t-18907910010 0791 13305862264 0371 2022.1.3 10:00:25 2022.1.3 10:05:11
注意:以上两类信息,先输入所有开户信息,再输入所有通讯信息,最后一行以“end”结束。
输出:
根据输入的详细通讯信息,计算所有已开户的用户的当月费用(精确到小数点后2位,单位元)。假设每个用户初始余额是100元。
每条通讯、短信信息均单独计费后累加,不是将所有信息累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略。
2.题目分析:
本题相较于第一题多了一个判断是手机用户还是座机用户已经通话双方的用户类型判断,采用的是创建新的通话记录成员的方法来解决。重点转为在输入阶段对用户类型的判断。
源码:
import java.text.*; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.Scanner; //import java.util.regex.Matcher; //import java.util.regex.Pattern; public class Main{ public static void main(String[] args) throws ParseException { Scanner in=new Scanner(System.in); // 正则表达式过滤多余数据 String judge1 = "u-[0][7][9][1][0-9]{7,8}\\s[0]"; String judge2 ="[t]-0[0-9]{10,11}\\s"+"0[0-9]{9,11}\\s"+"((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]|[0-9][1-9][0-9]{2}|[1-9][0-9]{3})\\.(((0?[13578]|1[02])\\.(0?"+"[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|((("+"[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))"+"\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])\\s"+"((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]|[0-9][1-9][0-9]{2}|[1-9][0-9]{3})\\.((([13578]|1[02])\\.("+"[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|((("+"[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))"+"\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])"; String judge3 ="u-[1][0-9]{10}\\s[1]"; String judge4 ="[t]-0[0-9]{9,11}\\s"+"1[0-9]{10}\\s"+"0[0-9]{2,3}\\s"+"((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]|[0-9][1-9][0-9]{2}|[1-9][0-9]{3})\\.(((0?[13578]|1[02])\\.(0?"+"[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|((("+"[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))"+"\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])\\s"+"((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]|[0-9][1-9][0-9]{2}|[1-9][0-9]{3})\\.((([13578]|1[02])\\.("+"[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|((("+"[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))"+"\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])"; String judge5 ="[t]-1[0-9]{10}\\s"+"0[0-9]{2,3}\\s"+"1[0-9]{10}\\s"+"0[0-9]{2,3}\\s"+"((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]|[0-9][1-9][0-9]{2}|[1-9][0-9]{3})\\.(((0?[13578]|1[02])\\.(0?"+"[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|((("+"[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))"+"\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])\\s"+"((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]|[0-9][1-9][0-9]{2}|[1-9][0-9]{3})\\.((([13578]|1[02])\\.("+"[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|((("+"[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))"+"\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])"; String judge6 ="[t]-1[0-9]{10}\\s"+"0[0-9]{2,3}\\s"+"0[0-9]{9,11}\\s"+"((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]|[0-9][1-9][0-9]{2}|[1-9][0-9]{3})\\.(((0?[13578]|1[02])\\.(0?"+"[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|((("+"[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))"+"\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])\\s"+"((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]|[0-9][1-9][0-9]{2}|[1-9][0-9]{3})\\.((([13578]|1[02])\\.("+"[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|((("+"[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))"+"\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])"; String s=""; User user; User user1; ArrayList<User> users=new ArrayList<User>(); String time; Date dd; s=in.nextLine(); ArrayList<String> s0=new ArrayList<String>(); while(!s.equals("end")) { boolean flag1=true; if(s.matches(judge1)||s.matches(judge3)) { user=new User(); String[] s2=s.split(" "); user.setNumber(s2[0]); boolean flag=true; if(s.substring(2,6).equals("0791")) { user.setRent(20); } else { user.setRent(15); } for(User u:users) { if(u.getNumber().equals(user.getNumber())) { flag=false; break; } } if(flag){ users.add(user); } } if(flag1) { if(s.matches(judge2)) { String[] s1=s.split(" "); for(int i=0;i<users.size();i++) { user1=users.get(i); if(s1[0].substring(2).equals(user1.getNumber().substring(2))) { Cost c=new Cost(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); time=s1[2]+" "+s1[3]; dd = (Date)sdf.parse(time); user1.setsTime(dd); c.setsTime(dd); time=s1[4]+" "+s1[5]; dd = (Date)sdf.parse(time); user1.seteTime(dd); c.seteTime(dd); double cost=0; if(s1[1].substring(0,4).equals("0791")){ cost=c.Cost1(0.1); } else if(s1[1].substring(0,4).matches("[0][7][9][0-9]")||s1[1].substring(0,4).equals("0701")) { cost=c.Cost1(0.3); } else { cost=c.Cost1(0.6); } user1.setCost(cost); users.set(i, user1); break; } } } if(s.matches(judge4)) { String[] s1=s.split(" "); for(int i=0;i<users.size();i++) { user1=users.get(i); if(s1[0].substring(2).equals(user1.getNumber().substring(2))) { Cost c=new Cost(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); time=s1[3]+" "+s1[4]; dd = (Date)sdf.parse(time); user1.setsTime(dd); c.setsTime(dd); time=s1[5]+" "+s1[6]; dd = (Date)sdf.parse(time); user1.seteTime(dd); c.seteTime(dd); double cost=0; if(s1[1].substring(0,4).equals("0791")){ cost=c.Cost1(0.1); } else if(s1[1].substring(0,4).matches("[0][7][9][0-9]")||s1[1].substring(0,4).equals("0701")) { cost=c.Cost1(0.3); } else { cost=c.Cost1(0.6); } user1.setCost(cost); users.set(i, user1); } if(s1[1].substring(0).equals(user1.getNumber().substring(2))) { Cost c=new Cost(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); time=s1[3]+" "+s1[4]; dd = (Date)sdf.parse(time); user1.setsTime(dd); c.setsTime(dd); time=s1[5]+" "+s1[6]; dd = (Date)sdf.parse(time); user1.seteTime(dd); c.seteTime(dd); double cost=0; if(s1[2].equals("0791")){ cost=c.Cost1(0); } else if(s1[2].matches("[0][7][9][0-9]")||s1[2].equals("0701")) { cost=c.Cost1(0); } else { cost=c.Cost1(0.3); } user1.setCost(cost); users.set(i, user1); } } } if(s.matches(judge5)) { String[] s1=s.split(" "); for(int i=0;i<users.size();i++) { user1=users.get(i); if(s1[0].substring(2).equals(user1.getNumber().substring(2))) { Cost c=new Cost(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); time=s1[4]+" "+s1[5]; dd = (Date)sdf.parse(time); user1.setsTime(dd); c.setsTime(dd); time=s1[6]+" "+s1[7]; dd = (Date)sdf.parse(time); user1.seteTime(dd); c.seteTime(dd); double cost=0; if(s1[1].equals("0791")&&s1[3].equals("0791")){ cost=c.Cost1(0.1); } else if(s1[1].equals("0791")&&(s1[3].matches("[0][7][9][0-9]")||s1[3].equals("0701"))){ cost=c.Cost1(0.2); } else if(s1[1].equals("0791")&&s1[3].matches("[0][0-9]{2,3}")){ cost=c.Cost1(0.3); } else if((s1[1].matches("[0][7][9][0-9]")||s1[1].matches("[0][7][0][1]"))&&(s1[3].matches("[0][7][9][0-9]")||s1[3].matches("[0][7][0][1]"))) { cost=c.Cost1(0.3); } else if(s1[1].matches("[0][0-9]{2,3}")) { cost=c.Cost1(0.6); } else { cost=c.Cost1(0.6); } user1.setCost(cost); users.set(i, user1); } if(s1[2].substring(0).equals(user1.getNumber().substring(2))) { Cost c=new Cost(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); time=s1[4]+" "+s1[5]; dd = (Date)sdf.parse(time); user1.setsTime(dd); c.setsTime(dd); time=s1[6]+" "+s1[7]; dd = (Date)sdf.parse(time); user1.seteTime(dd); c.seteTime(dd); double cost=0; if(s1[3].equals("0791")){ cost=c.Cost1(0); } else { cost=c.Cost1(0.3); } user1.setCost(cost); users.set(i, user1); } } } if(s.matches(judge6)) { String[] s1=s.split(" "); for(int i=0;i<users.size();i++) { user1=users.get(i); if(s1[0].substring(2).equals(user1.getNumber().substring(2))) { Cost c=new Cost(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); time=s1[3]+" "+s1[4]; dd = (Date)sdf.parse(time); user1.setsTime(dd); c.setsTime(dd); time=s1[5]+" "+s1[6]; dd = (Date)sdf.parse(time); user1.seteTime(dd); c.seteTime(dd); double cost=0; if(s1[1].equals("0791")&&s1[2].substring(0,4).equals("0791")){ cost=c.Cost1(0.1); } else if(s1[1].equals("0791")&&(s1[2].substring(0,4).matches("[0][7][9][0-9]")||s1[2].substring(0,4).equals("0701"))){ cost=c.Cost1(0.2); } else if(s1[1].equals("0791")&&s1[2].substring(0,4).matches("[0][0-9]{1,3}")){ cost=c.Cost1(0.3); } else if(s1[1].matches("[0][7][9][0-9]")&&(s1[2].substring(0,4).matches("[0][7][9][0-9]")||s1[2].substring(0,4).equals("0701"))) { cost=c.Cost1(0.3); } else if(s1[1].matches("[0][0-9]{1,3}")){ cost=c.Cost1(0.6); } else { cost=c.Cost1(0.6); } user1.setCost(cost); users.set(i, user1); } if(s1[2].equals(user1.getNumber().substring(2))) { Cost c=new Cost(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); time=s1[3]+" "+s1[4]; dd = (Date)sdf.parse(time); user1.setsTime(dd); c.setsTime(dd); time=s1[5]+" "+s1[6]; dd = (Date)sdf.parse(time); user1.seteTime(dd); c.seteTime(dd); double cost=0; user1.setCost(cost); users.set(i, user1); } } } } s=in.nextLine(); } Collections.sort(users,new Comparator<User>(){ @Override public int compare(User o1,User o2) { return o1.getNumber().substring(2).compareTo(o2.getNumber().substring(2)); } }); for(User user2:users) { double n=user2.getBalance()-user2.calCost()-user2.getRent(); System.out.println(user2.getNumber().substring(2)+" "+ new DecimalFormat("0.0#").format(user2.calCost())+" "+new DecimalFormat("0.0#").format(n)); } /* for(User user2:users){ if(user2.getNumber().substring(2,6).equals("0791")) { double n=user2.getBalance()-user2.calCost()-user2.getRent(); System.out.println(user2.getNumber().substring(2)+" "+ new DecimalFormat("0.0#").format(user2.calCost())+" "+new DecimalFormat("0.0#").format(n)); } } for(User user2:users){ if(!(user2.getNumber().substring(2,6).equals("0791"))) { double n=user2.getBalance()-user2.calCost()-user2.getRent(); System.out.println(user2.getNumber().substring(2)+" "+ new DecimalFormat("0.0#").format(user2.calCost())+" "+new DecimalFormat("0.0#").format(n)); } }*/ in.close(); } } //用户类 class User{ // UserRecords userRecords=new UserRecords(); double balance=100; double cost=0; // ChargeMode chargeMode; String number; Date endT,startT; double rent=0; double calBalance() { return balance; } double calCost() { return cost; } void setCost(double cost) { this.cost+=cost; } Date geteTime() { return endT; } Date getsTime() { return startT; } void seteTime(Date d) { this.endT=d; } void setsTime(Date d) { this.startT=d; } double getRent() { return rent; } void setRent(double rent) { this.rent=rent; } // UserRecords getUserRecords() { // return userRecords; // } // void setUserRecords(UserRecords userRecords) { // this.userRecords=userRecords; // } double getBalance(){ return balance; } // ChargeMode getChargeMode() { // // return chargeMode; // } // void setChargeMode(ChargeMode chargeMode) { // this.chargeMode=chargeMode; // } String getNumber() { return number; } void setNumber(String number) { this.number=number; } } class Cost{ Date eTime; Date sTime; void seteTime(Date end) { this.eTime=end; } void setsTime(Date start) { this.sTime=start; } double Cost1(double a){ double cost=0; double t=(eTime.getTime()-sTime.getTime())/1000.0; if(t%60>0) { int b=(int)(t/60.0); double c=b*a; cost=c+a; } else{ cost=((int)t/60.0)*a; } return cost; } double Cost2(double a){ double cost=0; return cost; } }
相较于上次,这次做了修改,没有完全按照题目所给出的类图来构建
类图及复杂度:


三. 电信计费系列3-短信计费
1.题目要求
实现一个简单的电信计费程序,针对手机的短信采用如下计费方式:
1、接收短信免费,发送短信0.1元/条,超过3条0.2元/条,超过5条0.3元/条。
2、如果一次发送短信的字符数量超过10个,按每10个字符一条短信进行计算。
输入:
输入信息包括两种类型
1、逐行输入南昌市手机用户开户的信息,每行一个用户。
格式:u-号码 计费类型 (计费类型包括:0-座机 1-手机实时计费 2-手机A套餐 3-手机短信计费)
例如:u-13305862264 3
座机号码由区号和电话号码拼接而成,电话号码包含7-8位数字,区号最高位是0。
手机号码由11位数字构成,最高位是1。
本题只针对类型3-手机短信计费。
2、逐行输入本月某些用户的短信信息,短信的格式:
m-主叫号码,接收号码,短信内容 (短信内容只能由数字、字母、空格、英文逗号、英文句号组成)
m-18907910010 13305862264 welcome to jiangxi.
m-13305862264 18907910010 thank you.
注意:以上两类信息,先输入所有开户信息,再输入所有通讯信息,最后一行以“end”结束。
输出:
根据输入的详细短信信息,计算所有已开户的用户的当月短信费用(精确到小数点后2位,单位元)。假设每个用户初始余额是100元。
每条短信信息均单独计费后累加,不是将所有信息累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略。
本题只做格式的错误判断,无需做内容上不合理的判断,比如同一个电话两条通讯记录的时间有重合、开户号码非南昌市的号码、自己给自己打电话等,此类情况都当成正确的输入计算。但时间的输入必须符合要求,比如不能输入2022.13.61 28:72:65。
本题只考虑短信计费,不考虑通信费用以及月租费。
2.问题分析:
这题相较于前两次非常简单,因为不需要考虑通话信息直接分析短信计费就好了,属于结课福利(bushi)
源码:
2022-12-10
import java.text.*; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Scanner; public class Main{ public static void main(String[] args) throws ParseException { Scanner in=new Scanner(System.in); // 正则表达式过滤多余数据 String judge1 ="u-[1][0-9]{10}\\s[3]"; String judge2 ="[m]-[1][0-9]{10} [1][0-9]{10} [a-z0-9,. ]+"; String s=""; User user; ArrayList<User> users=new ArrayList<User>(); s=in.nextLine(); ArrayList<String> s0=new ArrayList<String>(); while(!s.equals("end")) { boolean flag1=true; if(s.matches(judge1)) { user=new User(); String[] s2=s.split(" "); user.setNumber(s2[0]); boolean flag=true; for(User u:users) { if(u.getNumber().equals(user.getNumber())) { flag=false; break; } } if(flag){ users.add(user); } } if(s.matches(judge2)) { //String[] s1=s.split(" "); for(int i=0;i<users.size();i++) { User user1=users.get(i); int n=0; if(s.substring(2,13).equals(user1.getNumber().substring(2))) { // user1.adds(s1[2]); if(s.substring(26).length()%10==0) { n=s.substring(26).length()/10; } else if(s.substring(26).length()>10) { n=s.substring(26).length()/10+1; } else { n=1; } user1.adds(n); users.set(i, user1); } } } s=in.nextLine(); } Collections.sort(users,new Comparator<User>(){ @Override public int compare(User o1,User o2) { return o1.getNumber().substring(2).compareTo(o2.getNumber().substring(2)); } }); for(User user2:users) { double n=user2.getBalance()-user2.getCost(); System.out.println(user2.getNumber().substring(2)+" "+ new DecimalFormat("0.0#").format(user2.getCost())+" "+new DecimalFormat("0.0#").format(n)); } in.close(); } } //用户类 class User{ double balance=100; double cost=0; double n=0; String number; double getCost() { if(n<=3) { cost=n*0.1; } else if(n<=5) { cost=3*0.1+(n-3)*0.2; } else { cost=3*0.1+2*0.2+(n-5)*0.3; } return cost; } double calBalance() { return balance; } void adds(int n) { this.n+=n; } double getn() { return n; } double getBalance(){ return balance; } String getNumber() { return number; } void setNumber(String number) { this.number=number; } }
类图及复杂度:


BUG及编写问题集合
这次最多问题的就是对动态数组操作的出错,比如说数组越界。然后在刚开始写的时候我还忘记了ArrayList有替换这个操作方法,采用的是普通的创建对象然后替换= = 然后就悲剧了,卡在循环里一直出不去还不知道原因,最后调试才发现问题所在。当输入不符合要求的内容时,如果没有提前做好异常处理则会报错,所以可以用到try catch来解决这一问题,对异常输入做好提前检测与修正。
总结
总的来说这三次作业并没有太难,只要仔细分析好问题,再结合学习的代码知识,想要编写一个大概的能运行能执行基本操作的程序不算太难。在此基础上慢慢细化一些细节部分,将代码功能补全,这个过程就需要我们发散思维,对可能出现的情况和问题在代码中给出相应的解决方案。最基本的比如说输入格式错误啊,除法计算时除数为0啊这些说出来都觉得平常但是代码中容易遗漏的东西。除此之外就是题目中隐含的一些要求和特殊情况,需要自己结合题意慢慢分析,再逐步完善。
这里特别要说一下完成这三次作业后我的收获,我可以说深刻地感受到了动态数组的重要性。对于需要批量处理的想同类型的对象,动态数组可以说是非常合适也十分便于操作的,不管是作为成员还是作为普通使用对象,我们都要在日后的学习中多使用动态数组。
浙公网安备 33010602011771号