JAVA PTA 第三次大作业
(1)前言:
这几次的大作业还是比较简单的,只需要按照题目给出的类图,对应的写出相应的类,框架已经给出,你只需要填充就行了,多看几遍题目的类图,理清类之间的关联差不多就能写出了。
题量也不是太多,快的话就一天的事(指的是写一天的代码)。
知识点涉及到继承,多态,SimpleDateFormat类。
(2)设计与分析:
7-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元。
每条通讯信息单独计费后累加,不是将所有时间累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略。
源代码:
import java.text.ParseException; import java.util.ArrayList; import java.util.Date; import java.util.Scanner; import java.text.SimpleDateFormat; public class Main { public static void main(String[] args) throws ParseException { String s ; Scanner sc= new Scanner(System.in); s= sc.nextLine(); Input in; ArrayList<User> user = new ArrayList<>(); CallRecord callRecord; while(!s.equals("end")){ in= new Input(s); if(in.UserLegal()){ User tep= new User(); tep.setNumber(in.Usercheck()[0]); user.add(tep); ChargeMode chargeMode= new LandlinePhoneCharging(); chargeMode.chargeRules.add(new LandPhonelnCityRule()); chargeMode.chargeRules.add(new LandPhoneProvinceRule()); chargeMode.chargeRules.add(new LandPhonelnlandRule()); tep.serChargeMode(chargeMode); } else if(in.RecordLegal()){ callRecord= new CallRecord(in.getstartTime(),in.getendTime(),in.getcallingAddressAreaCode(),in.getanswerAddressAreaCode()); User tep =null; for(User a:user) if(a.getNumber().equals(in.getcalling())) tep= a; if(tep!=null){ if(judgechargemode(callRecord.getCallingAddressAreaCode(),callRecord.getAnswerAddressAreaCode())==0){ tep.userRecords.addcallinglnCityRecords(callRecord); } if(judgechargemode(callRecord.getCallingAddressAreaCode(),callRecord.getAnswerAddressAreaCode())==1){ tep.userRecords.addcallinglnPrivinceRecords(callRecord); } if(judgechargemode(callRecord.getCallingAddressAreaCode(),callRecord.getAnswerAddressAreaCode())==2){ tep.userRecords.addcallinlnLandRecords(callRecord); }} } s= sc.nextLine(); } outans(user); } public static ArrayList<User> Coincident(ArrayList<User> user){ for (int i = 0; i < user.size()-1; i++) for (int j = i+1; j <user.size(); j++) if(user.get(i).number.equals(user.get(j).number)) user.remove(i); return user; } public static int calculate_minute(Date d1, Date d2){ long from = d1.getTime(); long after= d2.getTime(); int miao = (int )((after-from)/1000); int fen = (int) Math.ceil(miao*1.0/60); return fen; } public static int judgechargemode(String s1,String s2){ String isprovince="(079[0-9]|0701)"; String iscity="0791"; if(s2.matches(iscity)) return 0; if(s2.matches(isprovince)) return 1; return 2; } public static void outans(ArrayList<User> user){ user= Coincident(user); java.util.Collections.sort(user); for (User a :user) System.out.printf("%s %.1f %.1f\n",a.number,a.chargeMode.calCost(a.userRecords),a.balance-a.chargeMode.getMonthlyRent()-a.chargeMode.calCost(a.userRecords)); } static class User implements Comparable<User> { UserRecords userRecords= new UserRecords(); double balance = 100; ChargeMode chargeMode ; String number ; User(){ } User(String number ){ } double calBalance(){ return 0; } double calCost(){ return 0; } UserRecords getUserRecords(){ return userRecords; } void setUserRecords(UserRecords userRecords){ this.userRecords=userRecords; } double getBalance(){ return this.balance; } ChargeMode getChargeMode(){ return chargeMode; } void serChargeMode(ChargeMode chargeMode){ this.chargeMode=chargeMode; } String getNumber(){ return this.number; } void setNumber(String number){ this.number=number; } public int compareTo(User newuser){ return String.CASE_INSENSITIVE_ORDER.compare(this.number,newuser.number); } } static class UserRecords{ ArrayList<CallRecord> callinglnCityRecords= new ArrayList<>();//市内拨打电话 ArrayList<CallRecord> callinglnPrivinceRecords= new ArrayList<>();//省内(不含市内)拨打电话 ArrayList<CallRecord> callinlnLandRecords= new ArrayList<>();//省外拨打电话 ArrayList<CallRecord> answerlnCityRecords= new ArrayList<>();//市内接听电话 ArrayList<CallRecord> answerlnPrivinceRecords= new ArrayList<>();//省内(不含市内)接听电话 ArrayList<CallRecord> answerlnLandRecords= new ArrayList<>();//省外接听电话的记录 ArrayList<MessageRecord> sendMessageRecords= new ArrayList<>();//发送短信 ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<>();//接收短信的记录 public void addcallinglnCityRecords(CallRecord callRecord) { callinglnCityRecords.add(callRecord); } public void addcallinglnPrivinceRecords(CallRecord callRecord) { callinglnPrivinceRecords.add(callRecord); } public void addcallinlnLandRecords(CallRecord callRecord) { callinlnLandRecords.add(callRecord); } public void addanswerlnCityRecords(CallRecord callRecord) { answerlnCityRecords.add(callRecord); } public void addanswerlnPrivinceRecords(CallRecord callRecord) { answerlnPrivinceRecords.add(callRecord); } public void addanswerlnLandRecords(CallRecord callRecord) { answerlnLandRecords.add(callRecord); } public void addsendMessageRecords(MessageRecord callRecord) { sendMessageRecords.add(callRecord); } public void addreceiveMessageRecords(MessageRecord callRecord) { receiveMessageRecords.add(callRecord); } } public abstract static class CommunicationRecord { protected String callingNumber; protected String answerNumber; protected String getCallingNumber(){ return this.callingNumber; } public void setCallingNumber(String callingNumber){ this.callingNumber=callingNumber; } public String getAnswerNumber(){ return this.answerNumber; } public void setAnswerNumber(String answerNumber){ this.answerNumber=answerNumber; } } class MessageRecord extends CommunicationRecord{ private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } public abstract static class CallChargeRule extends ChargeRule{ public abstract double calCost(UserRecords records); } public static class CallRecord extends CommunicationRecord{ private Date startTime; private Date endTime ; private String callingAddressAreaCode;//拨号地点的区号 private String answerAddressAreaCode;//接听地点的区号 CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode){ this.startTime=startTime; this.endTime=endTime; this.callingAddressAreaCode=callingAddressAreaCode; this.answerAddressAreaCode=answerAddressAreaCode; } public Date getStartTime() { return startTime; } public String getAnswerAddressAreaCode() { return answerAddressAreaCode; } public void setAnswerAddressAreaCode(String answerAddressAreaCode) { this.answerAddressAreaCode = answerAddressAreaCode; } public String getCallingAddressAreaCode() { return callingAddressAreaCode; } public void setCallingAddressAreaCode(String callingAddressAreaCode) { this.callingAddressAreaCode = callingAddressAreaCode; } public Date getEndTime() { return endTime; } public void setEndTime(Date endTime) { this.endTime = endTime; } public void setStartTime(Date startTime) { this.startTime = startTime; } } public abstract static class ChargeMode{ ArrayList<ChargeRule> chargeRules = new ArrayList<>(); public abstract double calCost(UserRecords userRecords); public abstract double getMonthlyRent(); public ArrayList<ChargeRule> getChargeRules() { return chargeRules; } public void setChargeRules(ArrayList<ChargeRule> chargeRules) { this.chargeRules = chargeRules; } } public abstract static class ChargeRule{ abstract double calCost(UserRecords records); } static class Input{ String s ; Input(String a){ this.s = a; } boolean UserLegal(){ String [] ss= s.split(" "); if(ss.length!=2) return false; String legal= "u-(0701|079\\d){1}\\d{7,8}[\\ ][0-2]"; return s.matches(legal); } String[] Usercheck(){ s=s.substring(2); return s.split(" "); } boolean RecordLegal() throws ParseException { String[] ss = s.split(" "); if(ss.length!=6) return false; String legal = "[t]-[0-9]{10,12}"; String legal1 = "\\d{10,12}"; String legal2 = "((2[0-3])|([0-1]?[0-9])):[0-5][0-9]:[0-5][0-9]"; return ss[0].matches( legal ) && ss[1].matches(legal1) && checktime(ss[2]) && checktime(ss[4]) && ss[3].matches(legal2) && ss[5].matches(legal2); } public boolean checktime(String date) { if(!date.matches("[1-9]\\d{3}\\.\\d{1,2}\\.\\d{1,2}")) return false; if(!date.matches("\\d{4}\\.(\\d|[1-9]\\d)\\.(\\d|[1-9]\\d)")) return false; String[] num = date.split("\\."); int year = Integer.parseInt(num[0]); int month = Integer.parseInt(num[1]); int day = Integer.parseInt(num[2]); if(month<1||month>12) return false; if(day<1) return false; int[] months={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; if((year%400==0)||(year%4==0&&year%100!=0)) { months[2]++; } return day <= months[month]; } boolean isLegalDate(String s){ boolean judgeresult=true; //1、首先使用SimpleDateFormat初步进行判断,过滤掉注入 yyyy-01-32 或yyyy-00-0x等格式 //此处可根据实际需求进行调整,如需判断yyyy/MM/dd格式将参数改掉即可 SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd"); try{ //增加强判断条件,否则 诸如2022-02-29也可判断出去 format.setLenient(false); Date date =format.parse(s); //System.out.println(date); }catch(Exception e){ judgeresult=false; } String yearStr=s.split("\\.")[0]; if(yearStr.startsWith("0")||yearStr.length()!=4){ judgeresult=false; } return judgeresult; } Date getstartTime() throws ParseException { SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); String[] ss = s.split(" "); String d1=ss[2]+" "+ss[3]; Date date1= format.parse(d1); return date1; } Date getendTime() throws ParseException { SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); String[] ss = s.split(" "); String d2 = ss[4]+" "+ss[5]; Date date2= format.parse(d2); return date2; } int calculate_minute() throws ParseException { SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); String[] ss = s.split(" "); String d1=ss[2]+" "+ss[3]; String d2 = ss[4]+" "+ss[5]; Date date1= format.parse(d1); Date date2= format.parse(d2); long from = date1.getTime(); long after= date2.getTime(); int miao = (int )((after-from)/1000); int fen = (int) Math.ceil(miao*1.0/60); return fen; } String getcalling(){ String[] ss = s.split(" "); return ss[0].substring(2); } String getanswer(){ String[] ss = s.split(" "); return ss[1]; } String getcallingAddressAreaCode(){ String tep= s.substring(2); String[] ss=tep.split(" "); if(ss[0].length()==10) return ss[0].substring(0,3); return ss[0].substring(0,4); } String getanswerAddressAreaCode(){ String[] ss = s.split(" "); if(ss[1].length()==10) return ss[1].substring(0,3); return ss[1].substring(0,4); } } static class LandlinePhoneCharging extends ChargeMode{ double monthlyRent =20 ; public double calCost(UserRecords userRecords){ double sum=0; for(ChargeRule a:chargeRules){ sum+=a.calCost(userRecords); } return sum; } public double getMonthlyRent(){ return monthlyRent; } } static class LandPhonelnCityRule extends CallChargeRule{ public double calCost(UserRecords records){ double sum =0; for(CallRecord a:records.callinglnCityRecords) if(calculate_minute(a.getStartTime(),a.getEndTime())>=0) sum+=calculate_minute(a.getStartTime(),a.getEndTime()); return (sum*0.1); } } static class LandPhonelnlandRule extends CallChargeRule{ public double calCost (UserRecords records){ double sum =0; for(CallRecord a:records.callinlnLandRecords) if(calculate_minute(a.getStartTime(),a.getEndTime())>=0) sum+=calculate_minute(a.getStartTime(),a.getEndTime()); return (sum*0.6); } } static class LandPhoneProvinceRule extends CallChargeRule{ public double calCost (UserRecords records){ double sum =0; for(CallRecord a:records.callinglnPrivinceRecords) if(calculate_minute(a.getStartTime(),a.getEndTime())>=0) sum+=calculate_minute(a.getStartTime(),a.getEndTime()); return (sum*0.3); } } }
类图:

SourceMonitor生成报表:

一 . 首先是对输入进行检测。
1.用户检测
boolean UserLegal(){ String [] ss= s.split(" "); if(ss.length!=2) return false; String legal= "u-(0701|079\\d){1}\\d{7,8}[\\ ][0-2]"; return s.matches(legal); }
2.用户记录检测
boolean RecordLegal() throws ParseException { String[] ss = s.split(" "); if(ss.length!=6) return false; String legal = "[t]-[0-9]{10,12}"; String legal1 = "\\d{10,12}"; String legal2 = "((2[0-3])|([0-1]?[0-9])):[0-5][0-9]:[0-5][0-9]"; return ss[0].matches( legal ) && ss[1].matches(legal1) && checktime(ss[2]) && checktime(ss[4]) && ss[3].matches(legal2) && ss[5].matches(legal2); }
public boolean checktime(String date) //检查年月日的合理性 { if(!date.matches("[1-9]\\d{3}\\.\\d{1,2}\\.\\d{1,2}")) return false; if(!date.matches("\\d{4}\\.(\\d|[1-9]\\d)\\.(\\d|[1-9]\\d)")) return false; String[] num = date.split("\\."); int year = Integer.parseInt(num[0]); int month = Integer.parseInt(num[1]); int day = Integer.parseInt(num[2]); if(month<1||month>12) return false; if(day<1) return false; int[] months={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; if((year%400==0)||(year%4==0&&year%100!=0)) { months[2]++; } return day <= months[month]; }
时间的检测也可以用SimpleDateFormat类进行检测。
boolean isLegalDate(String s){ if(!s.matches("[1-9]\\d{3}\\.\\d{1,2}\\.\\d{1,2}")) return false; if(!s.matches("\\d{4}\\.(\\d|[1-9]\\d)\\.(\\d|[1-9]\\d)")) return false; boolean judgeresult=true; //1、首先使用SimpleDateFormat初步进行判断,过滤掉注入 yyyy-01-32 或yyyy-00-0x等格式 //此处可根据实际需求进行调整,如需判断yyyy/MM/dd格式将参数改掉即可 SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd"); try{ //增加强判断条件,否则 诸如2022-02-29也可判断出去 format.setLenient(false); Date date =format.parse(s); //System.out.println(date); }catch(Exception e){ judgeresult=false; } // //由于上述方法只能验证正常的日期格式,像诸如 0001-01-01、11-01-01,10001-01-01等无法校验,此处再添加校验年费是否合法 // String yearStr=s.split(".")[0]; // if(yearStr.startsWith("0")||yearStr.length()!=4){ // judgeresult=false; // } return judgeresult; }
3.还有一些对输入的处理
Date getstartTime() throws ParseException { SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); String[] ss = s.split(" "); String d1=ss[2]+" "+ss[3]; Date date1= format.parse(d1); return date1; } Date getendTime() throws ParseException { SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); String[] ss = s.split(" "); String d2 = ss[4]+" "+ss[5]; Date date2= format.parse(d2); return date2; } int calculate_minute() throws ParseException { SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); String[] ss = s.split(" "); String d1=ss[2]+" "+ss[3]; String d2 = ss[4]+" "+ss[5]; Date date1= format.parse(d1); Date date2= format.parse(d2); long from = date1.getTime(); long after= date2.getTime(); int miao = (int )((after-from)/1000); int fen = (int) Math.ceil(miao*1.0/60); return fen; } String getcalling(){ String[] ss = s.split(" "); return ss[0].substring(2); } String getanswer(){ String[] ss = s.split(" "); return ss[1]; } String getcallingAddressAreaCode(){ String tep= s.substring(2); String[] ss=tep.split(" "); if(ss[0].length()==10) return ss[0].substring(0,3); return ss[0].substring(0,4); } String getanswerAddressAreaCode(){ String[] ss = s.split(" "); if(ss[1].length()==10) return ss[1].substring(0,3); return ss[1].substring(0,4); }
二 . 进行数据处理
while(!s.equals("end")){ in= new Input(s); if(in.UserLegal()){ User tep= new User(); tep.setNumber(in.Usercheck()[0]); user.add(tep); ChargeMode chargeMode= new LandlinePhoneCharging(); chargeMode.chargeRules.add(new LandPhonelnCityRule()); chargeMode.chargeRules.add(new LandPhoneProvinceRule()); chargeMode.chargeRules.add(new LandPhonelnlandRule()); tep.serChargeMode(chargeMode); } else if(in.RecordLegal()){ callRecord= new CallRecord(in.getstartTime(),in.getendTime(),in.getcallingAddressAreaCode(),in.getanswerAddressAreaCode()); User tep =null; for(User a:user) if(a.getNumber().equals(in.getcalling())) tep= a; if(tep!=null){ if(judgechargemode(callRecord.getCallingAddressAreaCode(),callRecord.getAnswerAddressAreaCode())==0){ tep.userRecords.addcallinglnCityRecords(callRecord); } if(judgechargemode(callRecord.getCallingAddressAreaCode(),callRecord.getAnswerAddressAreaCode())==1){ tep.userRecords.addcallinglnPrivinceRecords(callRecord); } if(judgechargemode(callRecord.getCallingAddressAreaCode(),callRecord.getAnswerAddressAreaCode())==2){ tep.userRecords.addcallinlnLandRecords(callRecord); }} } s= sc.nextLine(); }
三 . 计算金额
public double calCost(UserRecords userRecords){ double sum=0; for(ChargeRule a:chargeRules){ sum+=a.calCost(userRecords); } return sum; }
在每个计费规则中都有相应的计算 在这就放市内的
public double calCost(UserRecords records){ double sum =0; for(CallRecord a:records.callinglnCityRecords) if(calculate_minute(a.getStartTime(),a.getEndTime())>=0) sum+=calculate_minute(a.getStartTime(),a.getEndTime()); return (sum*0.1); }
public static int calculate_minute(Date d1, Date d2){ long from = d1.getTime(); long after= d2.getTime(); int miao = (int )((after-from)/1000); int fen = (int) Math.ceil(miao*1.0/60); return fen; }
四 .输出数据结果
public static void outans(ArrayList<User> user){ user= Coincident(user);//去重 java.util.Collections.sort(user);//排序 for (User a :user) System.out.printf("%s %.1f %.1f\n",a.number,a.chargeMode.calCost(a.userRecords),a.balance-a.chargeMode.getMonthlyRent()-a.chargeMode.calCost(a.userRecords)); }
7-1 电信计费系列2-手机+座机计费
实现南昌市电信分公司的计费程序,假设该公司针对手机和座机用户分别采取了两种计费方案,分别如下:
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元。
每条通讯、短信信息均单独计费后累加,不是将所有信息累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略
源代码:
import java.lang.reflect.Array; import java.text.ParseException; import java.util.*; import java.text.SimpleDateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.text.DateFormat; import java.util.ArrayList; import java.util.Date; import static java.util.Arrays.sort; public class Main { public static void main(String[] args) throws ParseException { String s ; Scanner sc= new Scanner(System.in); s= sc.nextLine(); Input in; ArrayList<User> user = new ArrayList<>(); CommunicationRecord callRecord = new CallRecord(); while(!s.equals("end")){ in= new Input(s); in.LandlinePhone(user, (CallRecord) callRecord); s= sc.nextLine(); } outans(user); // u-18907910010 3 // m-18907910010 13305862264 aaaaaaaaaaaa // m-18907910010 13305862264 aaaaaaa. // m-18907910010 13305862264 bb,bbbb // end } public static int calculate_minute(Date d1, Date d2){ long from = d1.getTime(); long after= d2.getTime(); int miao = (int )((after-from)/1000); int fen = (int) Math.ceil(miao*1.0/60); return fen; } public static int judgechargemode(String s1,String s2){ return judgechargemodes1(s1)*10+judgechargemodes2(s2); } public static int judgechargemodes2(String s2){ String isprovince="(079[0-9]|0701)"; String iscity="0791"; if(s2.matches(iscity)) return 1; if(s2.matches(isprovince)) return 2; return 3; } public static int judgechargemodes1(String s1){ String isprovince="(079[0-9]|0701)"; String iscity="0791"; if(s1.matches(iscity)) return 1; if(s1.matches(isprovince)) return 2; return 3; } public static void outans(ArrayList<User> user){ user= User.Coincident(user); Collections.sort(user); for (User a :user) { System.out.printf("%s %.1f %.1f\n", a.number,a.chargeMode.calCost(a.userRecords, Integer.parseInt(a.chageMode)), a.balance-a.chargeMode.getMonthlyRent(Integer.parseInt(a.chageMode))-a.chargeMode.calCost(a.userRecords,Integer.parseInt(a.chageMode))); } } } class Input{ static String s ; int flag=0; Input(String a){ this.s = a; } void LandlinePhone(ArrayList<User> user, CallRecord callRecord) throws ParseException { if(this.UserLegal()||this.PhoneNumberLegal()){ User tep= new User(); tep.setNumber(this.Usercheck()[0]); user.add(tep); ChargeMode chargeMode= new LandlinePhoneCharging(); chargeMode.chargeRules.add(new LandPhonelnCityRule()); chargeMode.chargeRules.add(new LandPhoneProvinceRule()); chargeMode.chargeRules.add(new LandPhonelnlandRule()); chargeMode.chargeRules.add(new SendMessgaeRule()); tep.serChargeMode(chargeMode); tep.chageMode = this.getChageMode(); } else if(this.RecordLegal()){ callRecord= new CallRecord(this.getstartTime(),this.getendTime(),this.getcallingAddressAreaCode(),this.getanswerAddressAreaCode()); User tep =null; User tep1 = null; user= User.Coincident(user); for(User a:user){ if(a.getNumber().equals(this.getcalling())) tep= a; if(a.getNumber().equals(this.getRecord())) tep1= a; } if(tep!=null) { //System.out.println(tep.number); if (judgechargemodes2(callRecord.getAnswerAddressAreaCode()) == 1) tep.userRecords.addcallinglnCityRecords(callRecord); if (judgechargemodes2(callRecord.getAnswerAddressAreaCode()) == 2) tep.userRecords.addcallinglnPrivinceRecords(callRecord); if (judgechargemodes2(callRecord.getAnswerAddressAreaCode()) == 3) tep.userRecords.addcallinlnLandRecords(callRecord); } if(tep1 != null){ if (judgechargemodes2(callRecord.getAnswerAddressAreaCode()) == 1) tep1.userRecords.addanswerlnCityRecords(callRecord); if (judgechargemodes2(callRecord.getAnswerAddressAreaCode()) == 2) tep1.userRecords.addanswerlnPrivinceRecords(callRecord); if (judgechargemodes2(callRecord.getAnswerAddressAreaCode()) == 3) tep1.userRecords.addanswerlnLandRecords(callRecord); } } else if(MessageLegal()){ String phone = s.substring(2,13); String messgae = s.substring(26); MessageRecord messageRecord = new MessageRecord(); messageRecord.setMessage(messgae); User tep =null; user= User.Coincident(user); for(User a:user){ if(a.getNumber().equals(phone)) tep= a; } if(tep!=null) { tep.userRecords.addsendMessageRecords(messageRecord); } } } boolean UserLegal(){ String [] ss= s.split(" "); if(ss.length!=2) return false; String legal= "u-(0701|079\\d){1}\\d{7,8}[\\ ][0-3]"; return s.matches(legal); } boolean PhoneNumberLegal(){ String [] ss= s.split(" "); if(ss.length!=2) return false; String legal= "u-1[3-9][\\d]{9}[\\ ][0-3]"; return s.matches(legal); } String[] Usercheck(){ String tep=s.substring(2); String[] ss = tep.split(" "); return ss; } boolean RecordLegal() throws ParseException { String[] ss = s.split(" "); //if(ss.length!=6) return false; String PhoneLegal= "1[3-9][\\d]{9}"; String AddressAreaCode = "[0]([\\d]{2}|[\\d]{3})"; String legal = "0[\\d]{2,3}[\\d]{7,8}"; String legal2 = "((2[0-3])|([0-1]?[0-9])):[0-5][0-9]:[0-5][0-9]"; if(ss.length==6) return (ss[0].matches("[t]-"+legal) )&& (ss[1].matches(legal)) && checktime(ss[2]) && checktime(ss[4]) && ss[3].matches(legal2) && ss[5].matches(legal2); if(ss.length==7&&ss[0].matches("[t]-"+PhoneLegal)) { flag=2; return (ss[0].matches("[t]-" + PhoneLegal)) && (ss[1].matches(AddressAreaCode)) && ss[2].matches(legal) && checktime(ss[3]) && checktime(ss[5]) && ss[4].matches(legal2) && ss[6].matches(legal2); } else if(ss.length==7&&ss[0].matches("[t]-"+legal)) { flag= 1; return (ss[0].matches("[t]-" + legal)) && (ss[1].matches(PhoneLegal)) && ss[2].matches(AddressAreaCode) && checktime(ss[3]) && checktime(ss[5]) && ss[4].matches(legal2) && ss[6].matches(legal2); } if(ss.length==8) { return (ss[0].matches("[t]-" + PhoneLegal)) && (ss[1].matches(AddressAreaCode)) && ss[2].matches(PhoneLegal) && (ss[3].matches(AddressAreaCode)) && checktime(ss[4]) && checktime(ss[6]) && ss[5].matches(legal2) && ss[7].matches(legal2); } return false; } boolean MessageLegal(){ if(s.length()<26){ return false; } String PhoneLegal= "1[3-9][\\d]{9}"; String messageLegal = "[\\d|\\w|\\s|\\.|\\,]{1,}"; String tep = s.substring(0,26); String message = s.substring(26); String ss[] = tep.split(" "); return ss[0].matches("m-"+PhoneLegal)&& ss[1].matches(PhoneLegal) && message.matches(messageLegal); } boolean isLegalDate(String s){ boolean judgeresult=true; //1、首先使用SimpleDateFormat初步进行判断,过滤掉注入 yyyy-01-32 或yyyy-00-0x等格式 //此处可根据实际需求进行调整,如需判断yyyy/MM/dd格式将参数改掉即可 SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd"); try{ //增加强判断条件,否则 诸如2022-02-29也可判断出去 format.setLenient(false); Date date =format.parse(s); //System.out.println(date); }catch(Exception e){ judgeresult=false; } // //由于上述方法只能验证正常的日期格式,像诸如 0001-01-01、11-01-01,10001-01-01等无法校验,此处再添加校验年费是否合法 // String yearStr=s.split(".")[0]; // if(yearStr.startsWith("0")||yearStr.length()!=4){ // judgeresult=false; // } return judgeresult; } public boolean checktime(String date) //检查年月日的合理性 { if(!date.matches("[1-9]\\d{3}\\.\\d{1,2}\\.\\d{1,2}")) return false; if(!date.matches("\\d{4}\\.(\\d|[1-9]\\d)\\.(\\d|[1-9]\\d)")) return false; String[] num = date.split("\\."); int year = Integer.parseInt(num[0]); int month = Integer.parseInt(num[1]); int day = Integer.parseInt(num[2]); if(month<1||month>12) return false; if(day<1) return false; int[] months={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; if((year%400==0)||(year%4==0&&year%100!=0)) { months[2]++; } return day <= months[month]; } Date getstartTime() throws ParseException { SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); String[] ss = s.split(" "); String d1 = null; if(ss.length==6) d1=ss[2]+" "+ss[3]; else if(ss.length==7) d1=ss[3]+" "+ss[4]; else if(ss.length==8) d1=ss[4]+" "+ss[5]; Date date1= format.parse(d1); return date1; } Date getendTime() throws ParseException { SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); String[] ss = s.split(" "); String d2 = null; if(ss.length==6) d2 = ss[4]+" "+ss[5]; else if(ss.length==7) d2 = ss[5]+" "+ss[6]; else if(ss.length==8) d2 = ss[6]+" "+ss[7]; Date date2= format.parse(d2); return date2; } static int calculate_minute() throws ParseException { SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); String[] ss = s.split(" "); String d1=ss[2]+" "+ss[3]; String d2 = ss[4]+" "+ss[5]; Date date1= format.parse(d1); Date date2= format.parse(d2); long from = date1.getTime(); long after= date2.getTime(); int miao = (int )((after-from)/1000); int fen = (int) Math.ceil(miao*1.0/60); return fen; } String getcalling(){ String[] ss = s.split(" "); return ss[0].substring(2); } String getRecord (){ String tep= s.substring(2); String[] ss=tep.split(" "); if(ss.length==8) return ss[2]; if(ss.length==7&&flag==2) return ss[2]; return ss[1]; } String getChageMode(){ String[] ss = s.split(" "); return ss[1]; } String getcallingAddressAreaCode(){ String tep= s.substring(2); String[] ss=tep.split(" "); if(ss.length==7&&flag==2){ return ss[1]; } if(ss.length==8){ return ss[1]; } if (ss[0].length() == 10) return ss[0].substring(0, 3); return ss[0].substring(0, 4); } String getanswerAddressAreaCode(){ String tep= s.substring(2); String[] ss=tep.split(" "); if(ss.length==7&&flag==1){ return ss[2]; } if(ss.length==7&&flag==2){ if(ss[2].length()==10) return ss[2].substring(0,3); return ss[2].substring(0,4); } if(ss.length==8){ return ss[3]; } if(ss[1].length()==10) return ss[1].substring(0,3); return ss[1].substring(0,4); } public static int judgechargemode(String s1,String s2){ return judgechargemodes1(s1)*10+judgechargemodes2(s2); } public static int judgechargemodes2(String s2){ String isprovince="(079[0-9]|0701)"; String iscity="0791"; if(s2.matches(iscity)) return 1; if(s2.matches(isprovince)) return 2; return 3; } public static int judgechargemodes1(String s1){ String isprovince="(079[0-9]|0701)"; String iscity="0791"; if(s1.matches(iscity)) return 1; if(s1.matches(isprovince)) return 2; return 3; } public static int calculate_minute(Date d1, Date d2){ long from = d1.getTime(); long after= d2.getTime(); int miao = (int )((after-from)/1000); int fen = (int) Math.ceil(miao*1.0/60); return fen; } } class User implements Comparable<User>{ UserRecords userRecords= new UserRecords(); double balance = 100; ChargeMode chargeMode ; String number ; String chageMode ; User(){ } User(String number ){ } public static ArrayList<User> Coincident(ArrayList<User> user){ for (int i = 0; i < user.size()-1; i++) for (int j = i+1; j <user.size(); j++) if(user.get(i).number.equals(user.get(j).number)) user.remove(i); return user; } double calBalance(){ return 0; } double calCost(){ return 0; } UserRecords getUserRecords(){ return userRecords; } void setUserRecords(UserRecords userRecords){ this.userRecords=userRecords; } double getBalance(){ return this.balance; } ChargeMode getChargeMode(){ return chargeMode; } void serChargeMode(ChargeMode chargeMode){ this.chargeMode=chargeMode; } String getNumber(){ return this.number; } void setNumber(String number){ this.number=number; } public int compareTo(User newuser){ return String.CASE_INSENSITIVE_ORDER.compare(this.number,newuser.number); } } class UserRecords{ ArrayList<CallRecord> callinglnCityRecords= new ArrayList<>();//市内拨打电话 ArrayList<CallRecord> callinglnPrivinceRecords= new ArrayList<>();//省内(不含市内)拨打电话 ArrayList<CallRecord> callinlnLandRecords= new ArrayList<>();//省外拨打电话 ArrayList<CallRecord> answerlnCityRecords= new ArrayList<>();//市内接听电话 ArrayList<CallRecord> answerlnPrivinceRecords= new ArrayList<>();//省内(不含市内)接听电话 ArrayList<CallRecord> answerlnLandRecords= new ArrayList<>();//省外接听电话的记录 ArrayList<MessageRecord> sendMessageRecords= new ArrayList<>();//发送短信 ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<>();//接收短信的记录 public void addcallinglnCityRecords(CallRecord callRecord) { callinglnCityRecords.add(callRecord); } public void addcallinglnPrivinceRecords(CallRecord callRecord) { callinglnPrivinceRecords.add(callRecord); } public void addcallinlnLandRecords(CallRecord callRecord) { callinlnLandRecords.add(callRecord); } public void addanswerlnCityRecords(CallRecord callRecord) { answerlnCityRecords.add(callRecord); } public void addanswerlnPrivinceRecords(CallRecord callRecord) { answerlnPrivinceRecords.add(callRecord); } public void addanswerlnLandRecords(CallRecord callRecord) { answerlnLandRecords.add(callRecord); } public void addsendMessageRecords(MessageRecord callRecord) { sendMessageRecords.add(callRecord); } public void addreceiveMessageRecords(MessageRecord callRecord) { receiveMessageRecords.add(callRecord); } } class CallRecord extends CommunicationRecord{ private Date startTime; private Date endTime ; private String callingAddressAreaCode;//拨号地点的区号 private String answerAddressAreaCode;//接听地点的区号 CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode){ this.startTime=startTime; this.endTime=endTime; this.callingAddressAreaCode=callingAddressAreaCode; this.answerAddressAreaCode=answerAddressAreaCode; } public CallRecord() { } public Date getStartTime() { return startTime; } public String getAnswerAddressAreaCode() { return answerAddressAreaCode; } public void setAnswerAddressAreaCode(String answerAddressAreaCode) { this.answerAddressAreaCode = answerAddressAreaCode; } public String getCallingAddressAreaCode() { return callingAddressAreaCode; } public void setCallingAddressAreaCode(String callingAddressAreaCode) { this.callingAddressAreaCode = callingAddressAreaCode; } public Date getEndTime() { return endTime; } public void setEndTime(Date endTime) { this.endTime = endTime; } public void setStartTime(Date startTime) { this.startTime = startTime; } } abstract class ChargeMode{ ArrayList<ChargeRule> chargeRules = new ArrayList<>(); public abstract double calCost(UserRecords userRecords,int n); public abstract double getMonthlyRent(int n); public ArrayList<ChargeRule> getChargeRules() { return chargeRules; } public void setChargeRules(ArrayList<ChargeRule> chargeRules) { this.chargeRules = chargeRules; } } abstract class ChargeRule{ abstract double calCost(UserRecords records,int n ); } abstract class CommunicationRecord { protected String callingNumber; protected String answerNumber; protected String getCallingNumber(){ return this.callingNumber; } public void setCallingNumber(String callingNumber){ this.callingNumber=callingNumber; } public String getAnswerNumber(){ return this.answerNumber; } public void setAnswerNumber(String answerNumber){ this.answerNumber=answerNumber; } } class LandlinePhoneCharging extends ChargeMode{ double monthlyRent =20 ; public double calCost(UserRecords userRecords,int n){ double sum=0; for(ChargeRule a:chargeRules){ sum+=a.calCost(userRecords,n); } return sum; } public double getMonthlyRent(int n){ if(n==0) return monthlyRent; else if(n==1) return 15; return 0; } } class LandPhonelnCityRule extends ChargeRule{ public double calCost(UserRecords records,int n){ double sum =0,sum1=0,sum2=0,sum3=0; double money=0; if(n==0) { for (CallRecord a : records.callinglnCityRecords) sum += Main.calculate_minute(a.getStartTime(), a.getEndTime()); money= (sum * 0.1); } if(n==1){ for (CallRecord a : records.callinglnCityRecords){ if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==1) sum1 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==2) sum2 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==3) sum3 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); } money= (sum1 * 0.1)+sum2*0.3+sum3*0.6; } return money; } } class LandPhonelnlandRule extends ChargeRule{ public double calCost (UserRecords records,int n ){ double sum =0,sum1=0,sum2=0,sum3=0; double money=0; if(n==0) { for (CallRecord a : records.callinlnLandRecords) sum += Main.calculate_minute(a.getStartTime(), a.getEndTime()); money+= (sum * 0.6); } if(n==1){ for (CallRecord a : records.callinlnLandRecords){ if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==1) sum1 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==2) sum2 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==3) sum3 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); } for (CallRecord a : records.answerlnLandRecords){ sum += Main.calculate_minute(a.getStartTime(), a.getEndTime()); } money= (sum1 * 0.3)+sum2*0.3+sum3*0.6+sum*0.3; } return money; } } class LandPhoneProvinceRule extends ChargeRule{ public double calCost (UserRecords records,int n ){ double sum =0,sum1=0,sum2=0,sum3=0; double money = 0; if(n==0) { for (CallRecord a : records.callinglnPrivinceRecords) sum += Main.calculate_minute(a.getStartTime(), a.getEndTime()); money= (sum * 0.3); } if(n==1){ for (CallRecord a : records.callinglnPrivinceRecords){ if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==1) sum1 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==2) sum2 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==3) sum3 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); } money= (sum1 * 0.2)+sum2*0.3+sum3*0.6; } return money; } } abstract class MessageChargeRule extends ChargeRule{ } class MessageRecord extends CommunicationRecord{ private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } class SendMessgaeRule extends MessageChargeRule{ @Override double calCost(UserRecords records, int n) { double sum =0; int w=0; if(n==3){ for(MessageRecord a:records.sendMessageRecords){ int num =(a.getMessage().length() + 10 - 1) / 10; w+=num; } if(w>3&&w<=5) sum+= (w-3)*0.2+0.3; else if(w>5) sum+= (w-5)*0.3+2*0.2+0.3; else sum+= w*0.1; } return sum; } }
类图
这类图是有点抽象。

SourceMonitor生成报表:

题目分析
这次的和上次的差不多就是多加了手机号的判断。
1.用户检测
要注意的是手机号的第二位只能在3-9之间(特地搜到的),这里有一个测试点。
boolean UserLegal(){ String [] ss= s.split(" "); if(ss.length!=2) return false; String legal= "u-(0701|079\\d){1}\\d{7,8}[\\ ][0-3]"; return s.matches(legal); } boolean PhoneNumberLegal(){ String [] ss= s.split(" "); if(ss.length!=2) return false; String legal= "u-1[3-9][\\d]{9}[\\ ][0-3]"; return s.matches(legal); }
2.用户记录检测
有手机号和座机号的时候有两种情况,我这用一个flag来标记来区分,时间的检测和上次是一样的。
boolean RecordLegal() throws ParseException { String[] ss = s.split(" "); //if(ss.length!=6) return false; String PhoneLegal= "1[3-9][\\d]{9}"; String AddressAreaCode = "[0]([\\d]{2}|[\\d]{3})"; String legal = "0[\\d]{2,3}[\\d]{7,8}"; String legal2 = "((2[0-3])|([0-1]?[0-9])):[0-5][0-9]:[0-5][0-9]"; if(ss.length==6) return (ss[0].matches("[t]-"+legal) )&& (ss[1].matches(legal)) && checktime(ss[2]) && checktime(ss[4]) && ss[3].matches(legal2) && ss[5].matches(legal2); if(ss.length==7&&ss[0].matches("[t]-"+PhoneLegal)) { flag=2; return (ss[0].matches("[t]-" + PhoneLegal)) && (ss[1].matches(AddressAreaCode)) && ss[2].matches(legal) && checktime(ss[3]) && checktime(ss[5]) && ss[4].matches(legal2) && ss[6].matches(legal2); } else if(ss.length==7&&ss[0].matches("[t]-"+legal)) { flag= 1; return (ss[0].matches("[t]-" + legal)) && (ss[1].matches(PhoneLegal)) && ss[2].matches(AddressAreaCode) && checktime(ss[3]) && checktime(ss[5]) && ss[4].matches(legal2) && ss[6].matches(legal2); } if(ss.length==8) { return (ss[0].matches("[t]-" + PhoneLegal)) && (ss[1].matches(AddressAreaCode)) && ss[2].matches(PhoneLegal) && (ss[3].matches(AddressAreaCode)) && checktime(ss[4]) && checktime(ss[6]) && ss[5].matches(legal2) && ss[7].matches(legal2); } return false; }
3.输入的处理
有两种情况,要注意判断返回。
String getcalling(){ String[] ss = s.split(" "); return ss[0].substring(2); } String getRecord (){ String tep= s.substring(2); String[] ss=tep.split(" "); if(ss.length==8) return ss[2]; if(ss.length==7&&flag==2) return ss[2]; return ss[1]; } String getChageMode(){ String[] ss = s.split(" "); return ss[1]; } String getcallingAddressAreaCode(){ String tep= s.substring(2); String[] ss=tep.split(" "); if(ss.length==7&&flag==2){ return ss[1]; } if(ss.length==8){ return ss[1]; } if (ss[0].length() == 10) return ss[0].substring(0, 3); return ss[0].substring(0, 4); } String getanswerAddressAreaCode(){ String tep= s.substring(2); String[] ss=tep.split(" "); if(ss.length==7&&flag==1){ return ss[2]; } if(ss.length==7&&flag==2){ if(ss[2].length()==10) return ss[2].substring(0,3); return ss[2].substring(0,4); } if(ss.length==8){ return ss[3]; } if(ss[1].length()==10) return ss[1].substring(0,3); return ss[1].substring(0,4); } public static int judgechargemode(String s1,String s2){ return judgechargemodes1(s1)*10+judgechargemodes2(s2); } public static int judgechargemodes2(String s2){ String isprovince="(079[0-9]|0701)"; String iscity="0791"; if(s2.matches(iscity)) return 1; if(s2.matches(isprovince)) return 2; return 3; } public static int judgechargemodes1(String s1){ String isprovince="(079[0-9]|0701)"; String iscity="0791"; if(s1.matches(iscity)) return 1; if(s1.matches(isprovince)) return 2; return 3; } public static int calculate_minute(Date d1, Date d2){ long from = d1.getTime(); long after= d2.getTime(); int miao = (int )((after-from)/1000); int fen = (int) Math.ceil(miao*1.0/60); return fen; }
4.数据处理
手机接电话也要记录下来。
void LandlinePhone(ArrayList<User> user, CallRecord callRecord) throws ParseException { if(this.UserLegal()||this.PhoneNumberLegal()){ User tep= new User(); tep.setNumber(this.Usercheck()[0]); user.add(tep); ChargeMode chargeMode= new LandlinePhoneCharging(); chargeMode.chargeRules.add(new LandPhonelnCityRule()); chargeMode.chargeRules.add(new LandPhoneProvinceRule()); chargeMode.chargeRules.add(new LandPhonelnlandRule()); chargeMode.chargeRules.add(new SendMessgaeRule()); tep.serChargeMode(chargeMode); tep.chageMode = this.getChageMode(); } else if(this.RecordLegal()){ callRecord= new CallRecord(this.getstartTime(),this.getendTime(),this.getcallingAddressAreaCode(),this.getanswerAddressAreaCode()); User tep =null; User tep1 = null; user= User.Coincident(user); for(User a:user){ if(a.getNumber().equals(this.getcalling())) tep= a; if(a.getNumber().equals(this.getRecord())) tep1= a; } if(tep!=null) { //System.out.println(tep.number); if (judgechargemodes2(callRecord.getAnswerAddressAreaCode()) == 1) tep.userRecords.addcallinglnCityRecords(callRecord); if (judgechargemodes2(callRecord.getAnswerAddressAreaCode()) == 2) tep.userRecords.addcallinglnPrivinceRecords(callRecord); if (judgechargemodes2(callRecord.getAnswerAddressAreaCode()) == 3) tep.userRecords.addcallinlnLandRecords(callRecord); } if(tep1 != null){ if (judgechargemodes2(callRecord.getAnswerAddressAreaCode()) == 1) tep1.userRecords.addanswerlnCityRecords(callRecord); if (judgechargemodes2(callRecord.getAnswerAddressAreaCode()) == 2) tep1.userRecords.addanswerlnPrivinceRecords(callRecord); if (judgechargemodes2(callRecord.getAnswerAddressAreaCode()) == 3) tep1.userRecords.addanswerlnLandRecords(callRecord); } } else if(MessageLegal()){ String phone = s.substring(2,13); String messgae = s.substring(26); MessageRecord messageRecord = new MessageRecord(); messageRecord.setMessage(messgae); User tep =null; user= User.Coincident(user); for(User a:user){ if(a.getNumber().equals(phone)) tep= a; } if(tep!=null) { tep.userRecords.addsendMessageRecords(messageRecord); } } }
5.计算金额
市内的情况
public double calCost(UserRecords records,int n){ double sum =0,sum1=0,sum2=0,sum3=0; double money=0; if(n==0) { for (CallRecord a : records.callinglnCityRecords) sum += Main.calculate_minute(a.getStartTime(), a.getEndTime()); money= (sum * 0.1); } if(n==1){ for (CallRecord a : records.callinglnCityRecords){ if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==1) sum1 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==2) sum2 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==3) sum3 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); } money= (sum1 * 0.1)+sum2*0.3+sum3*0.6; } return money; }
省内的情况
public double calCost (UserRecords records,int n ){ double sum =0,sum1=0,sum2=0,sum3=0; double money = 0; if(n==0) { for (CallRecord a : records.callinglnPrivinceRecords) sum += Main.calculate_minute(a.getStartTime(), a.getEndTime()); money= (sum * 0.3); } if(n==1){ for (CallRecord a : records.callinglnPrivinceRecords){ if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==1) sum1 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==2) sum2 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==3) sum3 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); } money= (sum1 * 0.2)+sum2*0.3+sum3*0.6; } return money; }
省外的情况
public double calCost (UserRecords records,int n ){ double sum =0,sum1=0,sum2=0,sum3=0; double money=0; if(n==0) { for (CallRecord a : records.callinlnLandRecords) sum += Main.calculate_minute(a.getStartTime(), a.getEndTime()); money+= (sum * 0.6); } if(n==1){ for (CallRecord a : records.callinlnLandRecords){ if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==1) sum1 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==2) sum2 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==3) sum3 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); } for (CallRecord a : records.answerlnLandRecords){ sum += Main.calculate_minute(a.getStartTime(), a.getEndTime()); } money= (sum1 * 0.3)+sum2*0.3+sum3*0.6+sum*0.3; } return money; }
7-1 电信计费系列3-短信计费
实现一个简单的电信计费程序,针对手机的短信采用如下计费方式:
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.
输出:
根据输入的详细短信信息,计算所有已开户的用户的当月短信费用(精确到小数点后2位,单位元)。假设每个用户初始余额是100元。
每条短信信息均单独计费后累加,不是将所有信息累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略。
本题只做格式的错误判断,无需做内容上不合理的判断,比如同一个电话两条通讯记录的时间有重合、开户号码非南昌市的号码、自己给自己打电话等,此类情况都当成正确的输入计算。但时间的输入必须符合要求,比如不能输入2022.13.61 28:72:65。
本题只考虑短信计费,不考虑通信费用以及月租费。
源代码:
import java.lang.reflect.Array; import java.text.ParseException; import java.util.*; import java.text.SimpleDateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.text.DateFormat; import java.util.ArrayList; import java.util.Date; import static java.util.Arrays.sort; public class Main { public static void main(String[] args) throws ParseException { String s ; Scanner sc= new Scanner(System.in); s= sc.nextLine(); Input in; ArrayList<User> user = new ArrayList<>(); CommunicationRecord callRecord = new CallRecord(); while(!s.equals("end")){ in= new Input(s); in.LandlinePhone(user, (CallRecord) callRecord); s= sc.nextLine(); } outans(user); } public static int calculate_minute(Date d1, Date d2){ long from = d1.getTime(); long after= d2.getTime(); int miao = (int )((after-from)/1000); int fen = (int) Math.ceil(miao*1.0/60); return fen; } public static int judgechargemode(String s1,String s2){ return judgechargemodes1(s1)*10+judgechargemodes2(s2); } public static int judgechargemodes2(String s2){ String isprovince="(079[0-9]|0701)"; String iscity="0791"; if(s2.matches(iscity)) return 1; if(s2.matches(isprovince)) return 2; return 3; } public static int judgechargemodes1(String s1){ String isprovince="(079[0-9]|0701)"; String iscity="0791"; if(s1.matches(iscity)) return 1; if(s1.matches(isprovince)) return 2; return 3; } public static void outans(ArrayList<User> user){ user= User.Coincident(user); Collections.sort(user); for (User a :user) { System.out.printf("%s %.1f %.1f\n", a.number,a.chargeMode.calCost(a.userRecords, Integer.parseInt(a.chageMode)), a.balance-a.chargeMode.getMonthlyRent(Integer.parseInt(a.chageMode))-a.chargeMode.calCost(a.userRecords,Integer.parseInt(a.chageMode))); } } } class Input{ static String s ; int flag=0; Input(String a){ this.s = a; } void LandlinePhone(ArrayList<User> user, CallRecord callRecord) throws ParseException { if(this.UserLegal()||this.PhoneNumberLegal()){ User tep= new User(); tep.setNumber(this.Usercheck()[0]); user.add(tep); ChargeMode chargeMode= new LandlinePhoneCharging(); chargeMode.chargeRules.add(new LandPhonelnCityRule()); chargeMode.chargeRules.add(new LandPhoneProvinceRule()); chargeMode.chargeRules.add(new LandPhonelnlandRule()); chargeMode.chargeRules.add(new SendMessgaeRule()); tep.serChargeMode(chargeMode); tep.chageMode = this.getChageMode(); } else if(MessageLegal()){ String phone = s.substring(2,13); String messgae = s.substring(26); MessageRecord messageRecord = new MessageRecord(); messageRecord.setMessage(messgae); User tep =null; user= User.Coincident(user); for(User a:user){ if(a.getNumber().equals(phone)) tep= a; } if(tep!=null) { tep.userRecords.addsendMessageRecords(messageRecord); } } } boolean UserLegal(){ String [] ss= s.split(" "); if(ss.length!=2) return false; String legal= "u-(0701|079\\d){1}\\d{7,8}[\\ ][0-3]"; return s.matches(legal); } boolean PhoneNumberLegal(){ String [] ss= s.split(" "); if(ss.length!=2) return false; String legal= "u-1[3-9][\\d]{9}[\\ ][0-3]"; return s.matches(legal); } String[] Usercheck(){ String tep=s.substring(2); String[] ss = tep.split(" "); return ss; } boolean MessageLegal(){ if(s.length()<26){ return false; } String PhoneLegal= "1[3-9][\\d]{9}"; String messageLegal = "[\\d|\\w|\\s|\\.|\\,]{1,}"; String tep = s.substring(0,26); String message = s.substring(26); String ss[] = tep.split(" "); return ss[0].matches("m-"+PhoneLegal)&& ss[1].matches(PhoneLegal) && message.matches(messageLegal); } public boolean checktime(String date) //检查年月日的合理性 { if(!date.matches("[1-9]\\d{3}\\.\\d{1,2}\\.\\d{1,2}")) return false; if(!date.matches("\\d{4}\\.(\\d|[1-9]\\d)\\.(\\d|[1-9]\\d)")) return false; String[] num = date.split("\\."); int year = Integer.parseInt(num[0]); int month = Integer.parseInt(num[1]); int day = Integer.parseInt(num[2]); if(month<1||month>12) return false; if(day<1) return false; int[] months={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; if((year%400==0)||(year%4==0&&year%100!=0)) months[2]++; return day <= months[month]; } static int calculate_minute() throws ParseException { SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); String[] ss = s.split(" "); String d1=ss[2]+" "+ss[3]; String d2 = ss[4]+" "+ss[5]; Date date1= format.parse(d1); Date date2= format.parse(d2); long from = date1.getTime(); long after= date2.getTime(); int miao = (int )((after-from)/1000); int fen = (int) Math.ceil(miao*1.0/60); return fen; } String getcalling(){ String[] ss = s.split(" "); return ss[0].substring(2); } String getRecord (){ String tep= s.substring(2); String[] ss=tep.split(" "); if(ss.length==8) return ss[2]; if(ss.length==7&&flag==2) return ss[2]; return ss[1]; } String getChageMode(){ String[] ss = s.split(" "); return ss[1]; } String getcallingAddressAreaCode(){ String tep= s.substring(2); String[] ss=tep.split(" "); if(ss.length==7&&flag==2){ return ss[1]; } if(ss.length==8){ return ss[1]; } if (ss[0].length() == 10) return ss[0].substring(0, 3); return ss[0].substring(0, 4); } String getanswerAddressAreaCode(){ String tep= s.substring(2); String[] ss=tep.split(" "); if(ss.length==7&&flag==1){ return ss[2]; } if(ss.length==7&&flag==2){ if(ss[2].length()==10) return ss[2].substring(0,3); return ss[2].substring(0,4); } if(ss.length==8){ return ss[3]; } if(ss[1].length()==10) return ss[1].substring(0,3); return ss[1].substring(0,4); } public static int judgechargemode(String s1,String s2){ return judgechargemodes1(s1)*10+judgechargemodes2(s2); } public static int judgechargemodes2(String s2){ String isprovince="(079[0-9]|0701)"; String iscity="0791"; if(s2.matches(iscity)) return 1; if(s2.matches(isprovince)) return 2; return 3; } public static int judgechargemodes1(String s1){ String isprovince="(079[0-9]|0701)"; String iscity="0791"; if(s1.matches(iscity)) return 1; if(s1.matches(isprovince)) return 2; return 3; } public static int calculate_minute(Date d1, Date d2){ long from = d1.getTime(); long after= d2.getTime(); int miao = (int )((after-from)/1000); int fen = (int) Math.ceil(miao*1.0/60); return fen; } } class User implements Comparable<User>{ UserRecords userRecords= new UserRecords(); double balance = 100; ChargeMode chargeMode ; String number ; String chageMode ; User(){ } User(String number ){ } public static ArrayList<User> Coincident(ArrayList<User> user){ for (int i = 0; i < user.size()-1; i++) for (int j = i+1; j <user.size(); j++) if(user.get(i).number.equals(user.get(j).number)) user.remove(i); return user; } double calBalance(){ return 0; } double calCost(){ return 0; } UserRecords getUserRecords(){ return userRecords; } void setUserRecords(UserRecords userRecords){ this.userRecords=userRecords; } double getBalance(){ return this.balance; } ChargeMode getChargeMode(){ return chargeMode; } void serChargeMode(ChargeMode chargeMode){ this.chargeMode=chargeMode; } String getNumber(){ return this.number; } void setNumber(String number){ this.number=number; } public int compareTo(User newuser){ return String.CASE_INSENSITIVE_ORDER.compare(this.number,newuser.number); } } class UserRecords{ ArrayList<CallRecord> callinglnCityRecords= new ArrayList<>();//市内拨打电话 ArrayList<CallRecord> callinglnPrivinceRecords= new ArrayList<>();//省内(不含市内)拨打电话 ArrayList<CallRecord> callinlnLandRecords= new ArrayList<>();//省外拨打电话 ArrayList<CallRecord> answerlnCityRecords= new ArrayList<>();//市内接听电话 ArrayList<CallRecord> answerlnPrivinceRecords= new ArrayList<>();//省内(不含市内)接听电话 ArrayList<CallRecord> answerlnLandRecords= new ArrayList<>();//省外接听电话的记录 ArrayList<MessageRecord> sendMessageRecords= new ArrayList<>();//发送短信 ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<>();//接收短信的记录 public void addcallinglnCityRecords(CallRecord callRecord) { callinglnCityRecords.add(callRecord); } public void addcallinglnPrivinceRecords(CallRecord callRecord) { callinglnPrivinceRecords.add(callRecord); } public void addcallinlnLandRecords(CallRecord callRecord) { callinlnLandRecords.add(callRecord); } public void addanswerlnCityRecords(CallRecord callRecord) { answerlnCityRecords.add(callRecord); } public void addanswerlnPrivinceRecords(CallRecord callRecord) { answerlnPrivinceRecords.add(callRecord); } public void addanswerlnLandRecords(CallRecord callRecord) { answerlnLandRecords.add(callRecord); } public void addsendMessageRecords(MessageRecord callRecord) { sendMessageRecords.add(callRecord); } public void addreceiveMessageRecords(MessageRecord callRecord) { receiveMessageRecords.add(callRecord); } } class CallRecord extends CommunicationRecord{ private Date startTime; private Date endTime ; private String callingAddressAreaCode;//拨号地点的区号 private String answerAddressAreaCode;//接听地点的区号 CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode){ this.startTime=startTime; this.endTime=endTime; this.callingAddressAreaCode=callingAddressAreaCode; this.answerAddressAreaCode=answerAddressAreaCode; } public CallRecord() { } public Date getStartTime() { return startTime; } public String getAnswerAddressAreaCode() { return answerAddressAreaCode; } public void setAnswerAddressAreaCode(String answerAddressAreaCode) { this.answerAddressAreaCode = answerAddressAreaCode; } public String getCallingAddressAreaCode() { return callingAddressAreaCode; } public void setCallingAddressAreaCode(String callingAddressAreaCode) { this.callingAddressAreaCode = callingAddressAreaCode; } public Date getEndTime() { return endTime; } public void setEndTime(Date endTime) { this.endTime = endTime; } public void setStartTime(Date startTime) { this.startTime = startTime; } } abstract class ChargeMode{ ArrayList<ChargeRule> chargeRules = new ArrayList<>(); public abstract double calCost(UserRecords userRecords,int n); public abstract double getMonthlyRent(int n); public ArrayList<ChargeRule> getChargeRules() { return chargeRules; } public void setChargeRules(ArrayList<ChargeRule> chargeRules) { this.chargeRules = chargeRules; } } abstract class ChargeRule{ abstract double calCost(UserRecords records,int n ); } abstract class CommunicationRecord { protected String callingNumber; protected String answerNumber; protected String getCallingNumber(){ return this.callingNumber; } public void setCallingNumber(String callingNumber){ this.callingNumber=callingNumber; } public String getAnswerNumber(){ return this.answerNumber; } public void setAnswerNumber(String answerNumber){ this.answerNumber=answerNumber; } } class LandlinePhoneCharging extends ChargeMode{ double monthlyRent =20 ; public double calCost(UserRecords userRecords,int n){ double sum=0; for(ChargeRule a:chargeRules){ sum+=a.calCost(userRecords,n); } return sum; } public double getMonthlyRent(int n){ if(n==0) return monthlyRent; else if(n==1) return 15; return 0; } } class LandPhonelnCityRule extends ChargeRule{ public double calCost(UserRecords records,int n){ double sum =0,sum1=0,sum2=0,sum3=0; double money=0; if(n==0) { for (CallRecord a : records.callinglnCityRecords) sum += Main.calculate_minute(a.getStartTime(), a.getEndTime()); money= (sum * 0.1); } if(n==1){ for (CallRecord a : records.callinglnCityRecords){ if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==1) sum1 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==2) sum2 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==3) sum3 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); } money= (sum1 * 0.1)+sum2*0.3+sum3*0.6; } return money; } } class LandPhonelnlandRule extends ChargeRule{ public double calCost (UserRecords records,int n ){ double sum =0,sum1=0,sum2=0,sum3=0; double money=0; if(n==0) { for (CallRecord a : records.callinlnLandRecords) sum += Main.calculate_minute(a.getStartTime(), a.getEndTime()); money+= (sum * 0.6); } if(n==1){ for (CallRecord a : records.callinlnLandRecords){ if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==1) sum1 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==2) sum2 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==3) sum3 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); } for (CallRecord a : records.answerlnLandRecords){ sum += Main.calculate_minute(a.getStartTime(), a.getEndTime()); } money= (sum1 * 0.3)+sum2*0.3+sum3*0.6+sum*0.3; } return money; } } class LandPhoneProvinceRule extends ChargeRule{ public double calCost (UserRecords records,int n ){ double sum =0,sum1=0,sum2=0,sum3=0; double money = 0; if(n==0) { for (CallRecord a : records.callinglnPrivinceRecords) sum += Main.calculate_minute(a.getStartTime(), a.getEndTime()); money= (sum * 0.3); } if(n==1){ for (CallRecord a : records.callinglnPrivinceRecords){ if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==1) sum1 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==2) sum2 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); if(Main.judgechargemodes1(a.getCallingAddressAreaCode())==3) sum3 += Main.calculate_minute(a.getStartTime(), a.getEndTime()); } money= (sum1 * 0.2)+sum2*0.3+sum3*0.6; } return money; } } abstract class MessageChargeRule extends ChargeRule{ } class MessageRecord extends CommunicationRecord{ private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } class SendMessgaeRule extends MessageChargeRule{ @Override double calCost(UserRecords records, int n) { double sum =0; int w=0; if(n==3){ for(MessageRecord a:records.sendMessageRecords){ int num =(a.getMessage().length() + 10 - 1) / 10; w+=num; } if(w>3&&w<=5) sum+= (w-3)*0.2+0.3; else if(w>5) sum+= (w-5)*0.3+2*0.2+0.3; else sum+= w*0.1; } return sum; } }
类图

SourceMonitor生成报表:

题目分析
这题只需要写有关短信的,还是简单的,在前面加上短信计费方式,但不要将三次题目写在一起,会代码长度超出限制的。
计费代码
double calCost(UserRecords records, int n) { double sum =0; int w=0; if(n==3){ for(MessageRecord a:records.sendMessageRecords){ int num =(a.getMessage().length() + 10 - 1) / 10; w+=num; } if(w>3&&w<=5) sum+= (w-3)*0.2+0.3; else if(w>5) sum+= (w-5)*0.3+2*0.2+0.3; else sum+= w*0.1; } return sum; }
(3)采坑心得:
1. 在电信计费系列1-座机计费对于时间的检测不够严谨,比如月份以0开头,这个我调试了好久,呜呜呜。
if(!date.matches("[1-9]\\d{3}\\.\\d{1,2}\\.\\d{1,2}")) return false; if(!date.matches("\\d{4}\\.(\\d|[1-9]\\d)\\.(\\d|[1-9]\\d)")) return false;
就行了。
2.Date的getTime()函数得到的是毫秒数,转化为秒的话需要除以1000。
3.电信计费系列3-短信计费中的短信内容 (短信内容只能由数字、字母、空格、英文逗号、英文句号组成),不能只判断字符的长度。
4.手机号的第二位在3-9之间。
5.还有要对用户先去重。

(4)改进建议:
对相应题目的编码改进给出自己的见解,做到可持续改进
这几次的大作业相较之前的大作业来说整体难度有所下降,类的设计也基本都是按着题目给的类图来设计,大家的代码都大同小异。
感觉可以写一个工厂类,在里面进行判断,返回相应的类。
(5)总结:
对本阶段(10-16周)综合性总结,学到了什么,哪些地方需要进一步学习及研究,对教师、课程、作业、实验、课上及课下组织方式等方面的改进建议及意见。

浙公网安备 33010602011771号