BLOG-3

一、前言

java也已经学习了一个学期了,我现在感觉题目难度飞速提升,题量也加大了许多。就是感觉题目很复杂,需要很长的时间去理解。同时,也需要更加明确的思路。其次,在这一小段时间里,我确实感受到了迭代的重要性,如果第一道题目思路清晰,写的比较完整,那么在这道题目的基础上进行改动就会简单许多。相反,如果一开始就写的很乱,那么之后的迭代只会更难,这点我深有体会。

最近发布的三次PTA题目集中·主要考察移动业务资费问题,虽然给出了类图,但是还是需要考虑很多问题,可以使用正则表达式等来判断格式错误;根据类图,来确定类与类之间的关系;同时,还要分别计算不同情况下的费用。

二、设计与分析

1.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元。
每条通讯信息单独计费后累加,不是将所有时间累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。

错误处理:
输入数据中出现的不符合格式要求的行一律忽略。

建议类图:
参见图1、2、3,可根据理解自行调整:

 (1)首先按照类图分别建类,其次先判断用户是否存在,电话是否合法。
 private static void handlerPhone(String code) {
        String[] dataList = code.split(" ");
        String[] phoneList = dataList[0].split("-");
        //检测电话号码是否合法
        String phoneNumber = phoneList[1];
        if (!isPass(phoneNumber)) {
            return;
        }
        User user = null;
        //是否存在用户
        if (isExits(phoneNumber)) {
            return;
        } else {
            user = new User();
            user.setNumber(phoneNumber);
            user.setChargeMode(new LandlinePhoneCharging());

            users.add(user);
        }

    }

(2)其次,使用正则表达式来判断电话号码是否正确,座机号码除区号外由是7-8位数字组成。南昌市的区号:0791,江西省内各地市区号包括:0790~0799以及0701。这个正则表达式我感觉非常复杂,也写了好久。

 String code = "";
        //记录号码
        while (!((code = scanner.nextLine()).equals("end"))) {
            String c = "u-\\d{11,12}\\s0";
            if (code.matches(c)) {
                handlerPhone(code);
            } else if (code.startsWith("t-")) {
                String s = "t-(\\d){11,12}\\s(\\d){10,12}\\s((((1[6-9]|[2-9]\\d)\\d{2}).([13578]|1[02]).([1-9]|[12]\\d|3[01]))|(((1[6-9]|[2-9]\\d)\\d{2}).([13456789]|1[012]).([1-9]|[12]\\d|30))|(((1[6-9]|[2-9]\\d)\\d{2})-2-([1-9]|1\\d|2[0-8]))|(((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-2-29-)) (20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d\\s((((1[6-9]|[2-9]\\d)\\d{2}).([13578]|1[02]).([1-9]|[12]\\d|3[01]))|(((1[6-9]|[2-9]\\d)\\d{2}).([13456789]|1[012]).([1-9]|[12]\\d|30))|(((1[6-9]|[2-9]\\d)\\d{2})-2-([1-9]|1\\d|2[0-8]))|(((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-2-29-)) (20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d";

                if(code.matches(s))
                    handlerRecord(code);
            }
        }
        handlerPrint();

    }

(3)我个人感觉最重要的就是user类,包括用户的信息以及费用的计算,是整道题目的核心。其次,计算时间时,要注意时间单位的换算。代码如下

 class User {
    private UserRecords userRecords = new UserRecords();
    private double balance = 100;
    private ChargeMode chargeMode;
    private String number;

   
    public double calBalance() {
        double y=this.balance-this.calCost()-this.chargeMode.getMonthlyRent();
        return y;
        
    }

    
    public double calCost() {
        return chargeMode.calCost(userRecords);
    }

    public double getBalance() {
        return balance;
    }

    public UserRecords getUserRecords() {
        return userRecords;
    }

    public void setUserRecords(UserRecords userRecords) {
        this.userRecords = userRecords;
    }

    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;
    }

}

 

class MyUtil {
    private MyUtil() {
    }

    public static Long dateDiff(Date startTime, Date endTime) {
        // 按照传入的格式生成一个simpledateformate对象
        long nd = 1000 * 24 * 60 * 60;// 一天的毫秒数
        long nh = 1000 * 60 * 60;// 一小时的毫秒数
        long nm = 1000 * 60;// 一分钟的毫秒数
        long ns = 1000;// 一秒钟的毫秒数
        long diff;
        long day = 0;
        long hour = 0;
        long min = 0;
        long sec = 0;
        // 获得两个时间的毫秒时间差异
        try {
            diff = startTime.getTime() - endTime.getTime();
            day = diff / nd;// 计算差多少天
            hour = diff % nd / nh + day * 24;// 计算差多少小时
            min = diff % nd % nh / nm + day * 24 * 60;// 计算差多少分钟
            sec = diff % nd % nh % nm / ns;// 计算差多少秒
            System.out.println("hour=" + hour + ",min=" + min);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        if (sec > 0) {
            min++;
        }
        return min;
    }
    public static String formatMoney(double money) {
        DecimalFormat df = new DecimalFormat("#0.0");
        return df.format(money); // 单位元;
    }
}

最后,完整代码如下:

import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;

import java.util.Date;
public class Main {
    private static Scanner scanner = new Scanner(System.in);
    private static ArrayList<User> users = new ArrayList<>();

    public static void main(String[] args) throws ParseException {
        // write your code here
        String code = "";
        //记录号码
        while (!((code = scanner.nextLine()).equals("end"))) {
            String c = "u-\\d{11,12}\\s0";
            if (code.matches(c)) {
                handlerPhone(code);
            } else if (code.startsWith("t-")) {
                String s = "t-(\\d){11,12}\\s(\\d){10,12}\\s((((1[6-9]|[2-9]\\d)\\d{2}).([13578]|1[02]).([1-9]|[12]\\d|3[01]))|(((1[6-9]|[2-9]\\d)\\d{2}).([13456789]|1[012]).([1-9]|[12]\\d|30))|(((1[6-9]|[2-9]\\d)\\d{2})-2-([1-9]|1\\d|2[0-8]))|(((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-2-29-)) (20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d\\s((((1[6-9]|[2-9]\\d)\\d{2}).([13578]|1[02]).([1-9]|[12]\\d|3[01]))|(((1[6-9]|[2-9]\\d)\\d{2}).([13456789]|1[012]).([1-9]|[12]\\d|30))|(((1[6-9]|[2-9]\\d)\\d{2})-2-([1-9]|1\\d|2[0-8]))|(((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-2-29-)) (20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d";

                if(code.matches(s))
                    handlerRecord(code);
            }
        }
        handlerPrint();

    }

    
    private static void handlerPrint() {
        Collections.sort(users, new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return o1.getNumber().compareTo(o2.getNumber());
            }
        });
        for (User user : users) {
            System.out.println(user.getNumber() + " " +MyUtil.formatMoney(user.calCost()) + " " + user.calBalance());
        }
    }

    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");

    private static void handlerRecord(String code) throws ParseException {
        String[] dataList = code.split(" ");
        String number = dataList[0].split("-")[1];
        String numberTwo = dataList[1];
    
        if (isExits(number)) {
            User user = getUser(number);


            String numberTwoPrefix = numberTwo.substring(0, 4);
            String numberOnePrefix = number.substring(0, 4);

            CallRecord callRecord = new CallRecord();
            callRecord.setCallingNumber(number);
            
            callRecord.setAnswerNumber(numberTwo);
            
            callRecord.setAnswerAddressAreaCode(numberTwoPrefix);
            
            callRecord.setCallingAddressAreaCode(numberOnePrefix);
            
            callRecord.setStartTime(simpleDateFormat.parse(dataList[2] + " " + dataList[3]));
            callRecord.setEndTime(simpleDateFormat.parse(dataList[4] + " " + dataList[5]));

            ArrayList<ChargeRule> chargeRules = user.getChargeMode().getChargeRules();

            //自己添加记录 如果存在的话

            // 市内电话
            if (numberTwoPrefix.equals("0791")) {
                user.getUserRecords().addCallingInCityRecords(callRecord);

                LandPhoneInCityRule LandPhoneInCityRule = new LandPhoneInCityRule();

                chargeRules.add(LandPhoneInCityRule);
            } else if (isProvince(numberTwoPrefix)) {
                user.getUserRecords().addCallingInProvinceRecords(callRecord);

                LandPhoneInProvinceRule LandPhoneInProvinceRule = new LandPhoneInProvinceRule();

                chargeRules.add(LandPhoneInProvinceRule);
            } else {
                user.getUserRecords().addCallingInLandRecords(callRecord);

                LandPhoneInIandRule LandPhoneInIandRule = new LandPhoneInIandRule();

                chargeRules.add(LandPhoneInIandRule);
            }

        }
    }

    private static boolean isProvince(String prefixTwo) {
        String prefix = "079";
        for (int i = 0; i <= 9; i++) {
            if (prefixTwo.equals(prefix + (i + ""))) {
                return true;
            }
        }
        if (prefixTwo.equals("0701")) {
            return true;
        }
        return false;
    }

    private static User getUser(String number) {
        for (User user : users) {
            if (user.getNumber().equals(number)) {
                return user;
            }
        }
        return null;
    }

  
    private static void handlerPhone(String code) {
        String[] dataList = code.split(" ");
        String[] phoneList = dataList[0].split("-");
        //检测电话号码是否合法
        String phoneNumber = phoneList[1];
        if (!isPass(phoneNumber)) {
            return;
        }
        User user = null;
        //是否存在用户
        if (isExits(phoneNumber)) {
            return;
        } else {
            user = new User();
            user.setNumber(phoneNumber);
            user.setChargeMode(new LandlinePhoneCharging());

            users.add(user);
        }

    }

    private static boolean isExits(String phoneNumber) {
        for (User user : users) {
            if (user.getNumber().equals(phoneNumber)) {
                return true;
            }
        }
        return false;
    }

    private static boolean isPass(String number) {
        //invalid number if not in
        String substring = number.substring(0, 4);

        boolean flagPreFix = false;
        boolean flagLength = false;

        if (substring.equals("0791")) {
            flagPreFix = true;
        }
       
        

        flagLength = (number.substring(5).length() == 7 || number.substring(5).length() == 8);

        
        return true;
    }
}
class UserRecords{
    ArrayList<CallRecord> callingInCityRecords = new ArrayList<CallRecord>();
    ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<CallRecord>();
    ArrayList<CallRecord> callingInLandRecords = new ArrayList<CallRecord>();
    ArrayList<CallRecord> answerInCityRecords = new ArrayList<CallRecord>();
    ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<CallRecord>();
    ArrayList<CallRecord> answerInLandRecords = new ArrayList<CallRecord>();
    ArrayList<MessageRecord> sendMessageRecord = new ArrayList<MessageRecord>();
    ArrayList<MessageRecord> receiveMessageRecord = new ArrayList<MessageRecord>();
    public void addCallingInCityRecords(CallRecord callRecord){
        callingInCityRecords.add(callRecord);
    }
    public void addCallingInProvinceRecords(CallRecord callRecord){
        callingInProvinceRecords.add(callRecord);
    }
    public void addCallingInLandRecords(CallRecord callRecord){
        callingInLandRecords.add(callRecord);
    }
    public void addAnswerInCityRecords(CallRecord callRecord){
        answerInCityRecords.add(callRecord);
    }
    public void addAnswerInProvinceRecords(CallRecord callRecord){
        answerInProvinceRecords.add(callRecord);
    }
    public void addAnswerInLandRecords(CallRecord callRecord){
        answerInLandRecords.add(callRecord);
    }
    public void addSendMessageRecord(MessageRecord sendMessageRecord){
        this.sendMessageRecord.add(sendMessageRecord);
    }
    public void addReceiveMessageRecord(MessageRecord receiveMessageRecord){
        this.receiveMessageRecord.add(receiveMessageRecord);
    }
    public ArrayList<MessageRecord> getSendMessageRecord(){
        return sendMessageRecord;
    }
    public ArrayList<MessageRecord> getReceiveMessageRecord(){
        return receiveMessageRecord;
    }
    public ArrayList<CallRecord> getCallingInCityRecords(){
        return callingInCityRecords;
    }
    public ArrayList<CallRecord> getCallingInProvinceRecords(){
        return callingInProvinceRecords;
    }
    public ArrayList<CallRecord> getCallingInLandRecords(){
        return callingInLandRecords;
    }
    public ArrayList<CallRecord> getAnswerInCityRecords(){
        return answerInCityRecords;
    }
    public ArrayList<CallRecord> getAnswerInProvinceRecords(){
        return answerInProvinceRecords;
    }
    public ArrayList<CallRecord> getAnswerInLandRecords(){
        return answerInLandRecords;
    }
}

 class User {
    private UserRecords userRecords = new UserRecords();
    private double balance = 100;
    private ChargeMode chargeMode;
    private String number;

   
    public double calBalance() {
        double y=this.balance-this.calCost()-this.chargeMode.getMonthlyRent();
        return y;
        
    }

    
    public double calCost() {
        return chargeMode.calCost(userRecords);
    }

    public double getBalance() {
        return balance;
    }

    public UserRecords getUserRecords() {
        return userRecords;
    }

    public void setUserRecords(UserRecords userRecords) {
        this.userRecords = userRecords;
    }

    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;
    }

}
class MyUtil {
    private MyUtil() {
    }

    public static Long dateDiff(Date startTime, Date endTime) {
        // 按照传入的格式生成一个simpledateformate对象
        long nd = 1000 * 24 * 60 * 60;// 一天的毫秒数
        long nh = 1000 * 60 * 60;// 一小时的毫秒数
        long nm = 1000 * 60;// 一分钟的毫秒数
        long ns = 1000;// 一秒钟的毫秒数
        long diff;
        long day = 0;
        long hour = 0;
        long min = 0;
        long sec = 0;
        // 获得两个时间的毫秒时间差异
        try {
            diff = startTime.getTime() - endTime.getTime();
            day = diff / nd;// 计算差多少天
            hour = diff % nd / nh + day * 24;// 计算差多少小时
            min = diff % nd % nh / nm + day * 24 * 60;// 计算差多少分钟
            sec = diff % nd % nh % nm / ns;// 计算差多少秒
            System.out.println("hour=" + hour + ",min=" + min);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        if (sec > 0) {
            min++;
        }
        return min;
    }
    public static String formatMoney(double money) {
        DecimalFormat df = new DecimalFormat("#0.0");
        return df.format(money); // 单位元;
    }
}

    class MessageRecord extends CommunicationRecord{
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

   
}
class LandPhoneInProvinceRule extends CallChargeRule{
    public double calCost(ArrayList<CallRecord>callRecords){
        double ans=0;
        for(int i=0;i<callRecords.size();i++)
        {
            double a1=(callRecords.get(i).getEndTime().getTime()-callRecords.get(i).getStartTime().getTime())/1000.0/60.0;
            double b1=Math.ceil(a1)*0.3;
               ans=ans+b1;
        }
        return ans;

    }
}
class LandPhoneInIandRule extends CallChargeRule{
    public double calCost(ArrayList<CallRecord>callRecords){       
                double ans=0;
                for(int i=0;i<callRecords.size();i++)
                {
                    double a2=(callRecords.get(i).getEndTime().getTime()-callRecords.get(i).getStartTime().getTime())/1000.0/60.0;
                    double b2=Math.ceil(a2)*0.6;
                    
                    ans=ans+b2;
                }
                return ans;

    }
}
class LandPhoneInCityRule extends CallChargeRule{
    public double calCost(ArrayList<CallRecord>callRecords){
        double ans=0;
        for(int i=0;i<callRecords.size();i++)
        {
            double a=(callRecords.get(i).getEndTime().getTime()-callRecords.get(i).getStartTime().getTime())/1000.0/60.0;
            double b=Math.ceil(a)*0.1;
            
            ans=ans+b;
        }
        return ans;

            
    }
    
}
class LandlinePhoneCharging extends ChargeMode {
    private double monthlyRent=20.0;

        public double calCost(UserRecords userRecords){
            double x1=getChargeRules().get(0).calCost(userRecords.getCallingInCityRecords());
            double x2=getChargeRules().get(1).calCost(userRecords.getCallingInProvinceRecords());
            double x3=getChargeRules().get(2).calCost(userRecords.getCallingInLandRecords());
            return x1+x2+x3;
        }
        
        public double getMonthlyRent(){
            return monthlyRent;
        }
    }

abstract class CommunicationRecord {
    String callingNumber;
    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;
    }

    
}
 
abstract class chargeRules extends ChargeRule{
    public double calCost(ArrayList<CallRecord>callRecords){
        return 0;
    }
}
 class ChargeRule {

    public double calCost(ArrayList<CallRecord> callingInCityRecords) {
        // TODO 自动生成的方法存根
        return 0;
    }

}
abstract class ChargeMode {

    private ArrayList<ChargeRule> chargeRules= new ArrayList<ChargeRule>();
    private LandPhoneInCityRule landPhoneInCityRule=new LandPhoneInCityRule();
    private LandPhoneInProvinceRule landPhoneInProvinceRule=new LandPhoneInProvinceRule();
    private LandPhoneInIandRule landPhoneInIandRule=new LandPhoneInIandRule();
    public double calCost(UserRecords userRecords) {
        return 0;
        
    }
    public double getMonthlyRent() {
        return 0;
        
    }
    public ChargeMode() {
        chargeRules.add(landPhoneInCityRule);
        chargeRules.add(landPhoneInProvinceRule);
        chargeRules.add(landPhoneInIandRule);
    }
    public ArrayList<ChargeRule> getChargeRules() {
        return chargeRules;
    }
    public void setChargeRules(ArrayList<ChargeRule> chargeRules) {
        this.chargeRules = chargeRules;
    }
    
}

   
  
class CallRecord extends CommunicationRecord{
    private Date startTime;
    private Date endTime;
    private String callingAddressAreaCode;
    private String AnswerAddressAreaCode;
    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 getCallingAddressAreaCode() {
        return callingAddressAreaCode;
    }
    public void setCallingAddressAreaCode(String callingAddressAreaCode) {
        this.callingAddressAreaCode = callingAddressAreaCode;
    }
    public String getAnswerAddressAreaCode() {
        return AnswerAddressAreaCode;
    }
    public void setAnswerAddressAreaCode(String answerAddressAreaCode) {
        AnswerAddressAreaCode = answerAddressAreaCode;
    }
    
}

abstract class CallChargeRule extends ChargeRule{
    public abstract double calCost(ArrayList<CallRecord>callRecords);
}

 类图如下:

2.7-1 电信计费系列2-手机+座机计费

这道题目实际上是在第一题的基础上进行功能的增加,从第一题的只能座机打座机,新增了手机打座机,手机打手机等,要求更加繁琐,而这道题到最后我也没有全部写对,虽然所给的测试样例全部通过,但是还是具有格式错误的情况没有考虑到。

(1)首先,跟第一题一样,先判断用户的开户情况和号码的正确性。座机号码由区号和电话号码拼接而成,电话号码包含7-8位数字,区号最高位是0,

手机号码由11位数字构成,最高位是1。

(2)要注意各种情况的消费是不一样的,分清0.1、0.2、0.3、0.6应该在何时消费

class PhoneCharging extends ChargeMode {
    private double monthlyRent = 15;

    @Override
    public double calCost(UserRecords userRecords) {
        double price = 0;

        for (ChargeRule chargeRule : getChargeRules()) {

            if (chargeRule instanceof LandlinePhoneInCityRule) {
                price = price + chargeRule.calCost(userRecords.getCallingInCityRecords());
            } else if (chargeRule instanceof LandlinePhoneInProvinceRule) {//市内拨省外、省内漫游0.3
                price = price + chargeRule.calCost(userRecords.getCallingInProvinceRecords());
            } else if (chargeRule instanceof PhoneInProvinceRule) {//市内拨市内0.2
                price = price + chargeRule.calCost(userRecords.getCallingInProvinceRecords02());
            } else if (chargeRule instanceof PhoneInProvinceAnswerRule) {//漫游接听0.3
                ArrayList<CallRecord> answerInLandRecords = userRecords.getAnswerInLandRecords();
                price = price + chargeRule.calCost(answerInLandRecords);
            } else if (chargeRule instanceof LandlinePhoneInLandRule) {//省外长途0.6
                price = price + chargeRule.calCost(userRecords.getCallingInLandRecords());
            }
        }
        //todo

        return price;
    }


    @Override
    public double getMonthlyRent() {

        return monthlyRent;
    }
}

 

if (isExits(number)) {
                User user = getUser(number);
                UserRecords userRecords = user.getUserRecords();
                if (answerCode.equals("0791") && callingCode.equals("0791")) {//市内拨打
                    userRecords.addCallingInCityRecords(callRecord);
                } else if (isProvince(answerCode) && callingCode.equals("0791")) {//市内打省内
                    userRecords.addCallingInProvinceRecords02(callRecord);
                } else if (!isProvince(answerCode) && !answerCode.equals("0791") && callingCode.equals("0791")) {//市内打省外
                    userRecords.addCallingInProvinceRecords(callRecord);
                    handlerAnswerPhone(answerCode, callRecord.getAnswerNumber(), callRecord);
                } else if (!callingCode.equals("0791") && isProvince(callingCode)) {//省内漫游
                    userRecords.addCallingInProvinceRecords(callRecord);
                    handlerAnswerPhone(answerCode, callRecord.getAnswerNumber(), callRecord);
                } else if (!callingCode.equals("0791") && !isProvince(callingCode)) {//省外漫游
                    userRecords.addCallingInLandRecords(callRecord);
                    handlerAnswerPhone(answerCode, callRecord.getAnswerNumber(), callRecord);
                }
            }

完整代码如下:

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;

public class Main {
    private static Scanner scanner = new Scanner(System.in);
    private static ArrayList<User> users = new ArrayList<>();
    private static ArrayList<String> records = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        // write your code here
        String code = " ";

            users.clear();
            records.clear();

            while (!((code = scanner.nextLine()).equals("end"))) {
                if (code.startsWith("u-")) {
                    handlerPhone(code);
                } else if (code.startsWith("t-")) {
                    handlerRecord(code);
                    records.add(code);
                }
            }
            handlerPrint();

    }

    private static void handlerPrint() {
        Collections.sort(users, new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return o1.getNumber().compareTo(o2.getNumber());
            }
        });
        for (User user : users) {
            System.out.println(user.getNumber() + " " + MyUtil.formatMoney(user.calCost()) + " " + user.calBalance());
        }
    }

    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");

    private static void handlerRecord(String code) throws Exception {//此处修改
        if (records.contains(code)) return;
        /*座机打座机079186300001 079186300002 2022.1.3 08:00:00 2022.1.3 08:09:20*/
        /*座机打手机079186300001 13986300001 0371 2022.1.3 10:00:25 2022.1.3 10:05:11*/
        /*手机打座机13986300001 0371 079186300001 2022.1.3 08:00:00 2022.1.3 08:09:20*/
        /*手机打手机13811111111 0791 13811111110 020 2022.1.3 08:00:00 2022.1.3 08:09:20*/
        String[] dataList = code.split(" ");
        if (dataList.length == 6) {//座机互拨
            String number = dataList[0].split("-")[1];
            String numberTwo = dataList[1];

            if (!isPaseLandlinePhone2(number) || !isPaseLandlinePhone2(numberTwo)) {
                return;
            }

            if (isExits(number)) {
                User user = getUser(number);
                String numberTwoPrefix = numberTwo.substring(0, 4);
                String numberOnePrefix = number.substring(0, 4);

                CallRecord callRecord = new CallRecord();
                callRecord.setCallingNumber(number);
                callRecord.setAnswerNumber(numberTwo);
                callRecord.setAnswerAddressAreaCode(numberTwoPrefix);
                callRecord.setCallingAddressAreaCode(numberOnePrefix);
                callRecord.setStartTime(simpleDateFormat.parse(dataList[2] + " " + dataList[3]));
                callRecord.setEndTime(simpleDateFormat.parse(dataList[4] + " " + dataList[5]));

                if (numberTwoPrefix.equals("0791")) {
                    user.getUserRecords().addCallingInCityRecords(callRecord);
                } else if (isProvince(numberTwoPrefix)) {
                    user.getUserRecords().addCallingInProvinceRecords(callRecord);
                } else {
                    user.getUserRecords().addCallingInLandRecords(callRecord);
                }
            }
        } else if (dataList.length == 7) {//座机手机互拨
            if (isPassAreaNumber(dataList[2])) {//座机拨手机
                String number = dataList[0].split("-")[1];
                String numberOnePrefix = number.substring(0, 4);

                if (!isPaseLandlinePhone2(number) || !isPassPhone(dataList[1])) {
                    return;
                }

                CallRecord callRecord = new CallRecord();
                callRecord.setCallingNumber(number);
                callRecord.setAnswerNumber(dataList[1]);
                callRecord.setAnswerAddressAreaCode(dataList[2]);
                callRecord.setCallingAddressAreaCode(numberOnePrefix);
                callRecord.setStartTime(simpleDateFormat.parse(dataList[3] + " " + dataList[4]));
                callRecord.setEndTime(simpleDateFormat.parse(dataList[5] + " " + dataList[6]));

                if (isExits(number)) {
                    User user = getUser(number);
                    if (callRecord.getAnswerAddressAreaCode().equals("0791")) {//市内拨市内
                        user.getUserRecords().addCallingInCityRecords(callRecord);
                    } else if (isProvince(callRecord.getAnswerAddressAreaCode())) {//座机省内0.3
                        user.getUserRecords().addCallingInProvinceRecords(callRecord);
                    } else {//国际长途 0.6
                        user.getUserRecords().addCallingInLandRecords(callRecord);
                        //计算接电话的漫游
                        handlerAnswerPhone(callRecord.getAnswerAddressAreaCode(), callRecord.getAnswerNumber(), callRecord);
                    }
                } else {//如果是漫游,手机接听要收费
                    //计算接电话的漫游
                    handlerAnswerPhone(callRecord.getAnswerAddressAreaCode(), callRecord.getAnswerNumber(), callRecord);
                }
            } else if (dataList[2].length() > 4) {//手机拨座机
                String number = dataList[0].split("-")[1];

                if (!isPaseLandlinePhone2(dataList[2]) || !isPassPhone(number)) {
                    return;
                }

                if (isExits(number)) {
                    User user = getUser(number);
                    CallRecord callRecord = new CallRecord();
                    callRecord.setCallingNumber(number);
                    callRecord.setAnswerNumber(dataList[2]);
                    callRecord.setAnswerAddressAreaCode(dataList[2].substring(0, 4));
                    callRecord.setCallingAddressAreaCode(dataList[1]);
                    callRecord.setStartTime(simpleDateFormat.parse(dataList[3] + " " + dataList[4]));
                    callRecord.setEndTime(simpleDateFormat.parse(dataList[5] + " " + dataList[6]));


                    if (callRecord.getCallingAddressAreaCode().equals("0791")) {//手机市内拨打座机
                        user.getUserRecords().addCallingInCityRecords(callRecord);
                    } else if (isProvince(callRecord.getCallingAddressAreaCode())) {//手机省内漫游拨打座机
                        user.getUserRecords().addCallingInProvinceRecords(callRecord);
                    } else {//手机省外漫游
                        user.getUserRecords().addCallingInLandRecords(callRecord);
                        handlerAnswerPhone(callRecord.getAnswerAddressAreaCode(), callRecord.getAnswerNumber(), callRecord);
                    }
                }
            }
        } else if (dataList.length == 8) {//手机拨手机
            String number = dataList[0].split("-")[1];

            if (!isPassPhone(dataList[2]) || !isPassPhone(number) ||
                    !isPassAreaNumber(dataList[1]) || !isPassAreaNumber(dataList[3])) {
                return;
            }

            CallRecord callRecord = new CallRecord();
            callRecord.setCallingNumber(number);
            callRecord.setAnswerNumber(dataList[2]);
            callRecord.setCallingAddressAreaCode(dataList[1]);
            callRecord.setAnswerAddressAreaCode(dataList[3]);
            callRecord.setStartTime(simpleDateFormat.parse(dataList[4] + " " + dataList[5]));
            callRecord.setEndTime(simpleDateFormat.parse(dataList[6] + " " + dataList[7]));

            String answerCode = callRecord.getAnswerAddressAreaCode();
            String callingCode = callRecord.getCallingAddressAreaCode();

            if (isExits(number)) {
                User user = getUser(number);
                UserRecords userRecords = user.getUserRecords();
                if (answerCode.equals("0791") && callingCode.equals("0791")) {//市内拨打
                    userRecords.addCallingInCityRecords(callRecord);
                } else if (isProvince(answerCode) && callingCode.equals("0791")) {//市内打省内
                    userRecords.addCallingInProvinceRecords02(callRecord);
                } else if (!isProvince(answerCode) && !answerCode.equals("0791") && callingCode.equals("0791")) {//市内打省外
                    userRecords.addCallingInProvinceRecords(callRecord);
                    handlerAnswerPhone(answerCode, callRecord.getAnswerNumber(), callRecord);
                } else if (!callingCode.equals("0791") && isProvince(callingCode)) {//省内漫游
                    userRecords.addCallingInProvinceRecords(callRecord);
                    handlerAnswerPhone(answerCode, callRecord.getAnswerNumber(), callRecord);
                } else if (!callingCode.equals("0791") && !isProvince(callingCode)) {//省外漫游
                    userRecords.addCallingInLandRecords(callRecord);
                    handlerAnswerPhone(answerCode, callRecord.getAnswerNumber(), callRecord);
                }
            } else {//如果是漫游,手机接听要收费
                //计算接电话的漫游
                handlerAnswerPhone(callRecord.getAnswerAddressAreaCode(), callRecord.getAnswerNumber(), callRecord);
            }
        }

    }


    private static void handlerAnswerPhone(String answerCode, String answerNumber, CallRecord callRecord) throws Exception {
        if (!isProvince(answerCode) && !answerCode.equals("0791")) {
            if (isExits(answerNumber)) {
                User user = getUser(answerNumber);
                UserRecords userRecords = user.getUserRecords();
                userRecords.addAnswerInLandRecords(callRecord);
            }
        }
    }

    private static boolean isProvince(String prefixTwo) throws Exception {
        String prefix = "079";
        for (int i = 0; i <= 9; i++) {
            if (prefixTwo.equals(prefix + (i + ""))) {
                return true;
            }
        }
        if (prefixTwo.equals("0701")) {
            return true;
        }
        return false;
    }

    private static User getUser(String number) {
        for (User user : users) {
            if (user.getNumber().equals(number)) {
                return user;
            }
        }
        return null;
    }


    private static void handlerPhone(String code) throws Exception {
        String[] dataList = code.split(" ");
        String[] phoneList = dataList[0].split("-");


        String phoneNumber = phoneList[1];
        int numberType = getNumberType(phoneNumber);
        if (numberType == TYPE_PHONE_NUMBER) {
            if (!isPaseLandlinePhone(phoneNumber)) {
                return;
            }
        } else if (numberType == TYPE_PHONE) {
            if (!isPassPhone(phoneNumber)) {
                return;
            }
        }

        User user = null;

        if (isExits(phoneNumber)) {
            return;
        } else {
            user = new User();
            user.setNumber(phoneNumber);
            String type = dataList[1];
            if (type.equals("0")) {
                LandlinePhoneCharging landlinePhoneCharging = new LandlinePhoneCharging();
                //创建用户时创建计费规则
                addChargeRules(landlinePhoneCharging);
                user.setChargeMode(landlinePhoneCharging);
            } else if (type.equals("1")) {
                PhoneCharging phoneCharging = new PhoneCharging();
                //创建用户时创建计费规则
                addChargeRules(phoneCharging);
                user.setChargeMode(phoneCharging);
            }
            users.add(user);
        }

    }

    private static void addChargeRules(ChargeMode chargeMode) {
        ArrayList<ChargeRule> chargeRules = chargeMode.getChargeRules();
        LandlinePhoneInCityRule landlinePhoneInCityRule = new LandlinePhoneInCityRule();
        chargeRules.add(landlinePhoneInCityRule);
        LandlinePhoneInProvinceRule landlinePhoneInProvinceRule = new LandlinePhoneInProvinceRule();
        chargeRules.add(landlinePhoneInProvinceRule);
        LandlinePhoneInLandRule landlinePhoneInLandRule = new LandlinePhoneInLandRule();
        chargeRules.add(landlinePhoneInLandRule);

        PhoneInProvinceAnswerRule phoneInProvinceAnswerRule = new PhoneInProvinceAnswerRule();
        chargeRules.add(phoneInProvinceAnswerRule);
        PhoneInLandCallingRule phoneInLandCallingRule = new PhoneInLandCallingRule();
        chargeRules.add(phoneInLandCallingRule);
    }

    public static Integer TYPE_PHONE = 0;
    public static Integer TYPE_PHONE_NUMBER = 1;

    private static Integer getNumberType(String phoneNumber) {
        if (phoneNumber.startsWith("1")) {
            return TYPE_PHONE;
        } else if (phoneNumber.startsWith("0")) {
            return TYPE_PHONE_NUMBER;
        }
        return null;
    }

    private static boolean isExits(String phoneNumber) {
        for (User user : users) {
            if (user.getNumber().equals(phoneNumber)) {
                return true;
            }
        }
        return false;
    }

    private static boolean isPaseLandlinePhone(String number) throws Exception {
        String substring = number.substring(0, 4);
        boolean flagPreFix = false;
        boolean flagLength = false;
        if (substring.equals("0791")) {
            flagPreFix = true;
        }

        flagLength = (number.substring(4).length() == 7 || number.substring(4).length() == 8);
        return flagPreFix && flagLength;
    }

    private static boolean isPaseLandlinePhone2(String number) throws Exception {
        boolean flag = true;
        if (number.length() < 10 || number.length() > 12) {
            flag = false;
        }
        return flag;
    }

    private static boolean isPassPhone(String phoneNumber) throws Exception {
        if (phoneNumber.length() > 0 && !"1".equals(phoneNumber.substring(0, 1)))
            return false;
        return phoneNumber.length() == 11;
    }

    private static boolean isPassAreaNumber(String areaNumber) throws Exception {
        return areaNumber.length() == 3 || areaNumber.length() == 4;
    }
}

abstract class ChargeMode {
    private 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 {
    private double monthlyRent = 20;

    public double calCost(UserRecords userRecords) {
        double price = 0;

        for (ChargeRule chargeRule : getChargeRules()) {
            if (chargeRule instanceof LandlinePhoneInCityRule) {
                price = price + chargeRule.calCost(userRecords.getCallingInCityRecords());
            } else if (chargeRule instanceof LandlinePhoneInProvinceRule) {
                price = price + chargeRule.calCost(userRecords.getCallingInProvinceRecords());
            } else if (chargeRule instanceof LandlinePhoneInLandRule) {
                price = price + chargeRule.calCost(userRecords.getCallingInLandRecords());
            }
        }
        //todo

        return price;
    }


    @Override
    public double getMonthlyRent() {

        return monthlyRent;
    }
}


class PhoneCharging extends ChargeMode {
    private double monthlyRent = 15;

    @Override
    public double calCost(UserRecords userRecords) {
        double price = 0;

        for (ChargeRule chargeRule : getChargeRules()) {

            if (chargeRule instanceof LandlinePhoneInCityRule) {
                price = price + chargeRule.calCost(userRecords.getCallingInCityRecords());
            } else if (chargeRule instanceof LandlinePhoneInProvinceRule) {//市内拨省外、省内漫游0.3
                price = price + chargeRule.calCost(userRecords.getCallingInProvinceRecords());
            } else if (chargeRule instanceof PhoneInProvinceRule) {//市内拨市内0.2
                price = price + chargeRule.calCost(userRecords.getCallingInProvinceRecords02());
            } else if (chargeRule instanceof PhoneInProvinceAnswerRule) {//漫游接听0.3
                ArrayList<CallRecord> answerInLandRecords = userRecords.getAnswerInLandRecords();
                price = price + chargeRule.calCost(answerInLandRecords);
            } else if (chargeRule instanceof LandlinePhoneInLandRule) {//省外长途0.6
                price = price + chargeRule.calCost(userRecords.getCallingInLandRecords());
            }
        }
        //todo

        return price;
    }


    @Override
    public double getMonthlyRent() {

        return monthlyRent;
    }
}

class CallRecord extends CommunicationRecord {
    private Date startTime;
    private Date endTime;

    private String callingAddressAreaCode;

    private String answerAddressAreaCode;

    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 getCallingAddressAreaCode() {
        return callingAddressAreaCode;
    }

    public void setCallingAddressAreaCode(String callingAddressAreaCode) {
        this.callingAddressAreaCode = callingAddressAreaCode;
    }

    public String getAnswerAddressAreaCode() {
        return answerAddressAreaCode;
    }

    public void setAnswerAddressAreaCode(String answerAddressAreaCode) {
        this.answerAddressAreaCode = answerAddressAreaCode;
    }

    @Override
    public String toString() {
        return "CallRecord{" +
                "startTime=" + startTime +
                ", endTime=" + endTime +
                ", callingAddressAreaCode='" + callingAddressAreaCode + '\'' +
                ", answerAddressAreaCode='" + answerAddressAreaCode + '\'' +
                '}';
    }
}


abstract class CommunicationRecord {
    private String callingNumber;
    private 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 MessageRecord extends CommunicationRecord {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}


class MessageChargeRule extends ChargeRule {
    @Override
    public double calCost(ArrayList<CallRecord> callRecords) {
        return 0;
    }
}


class SendMessageRule extends MessageChargeRule {
    @Override
    public double calCost(ArrayList<CallRecord> callRecords) {
        return super.calCost(callRecords);
    }
}


abstract class CallChargeRule extends ChargeRule {

    public abstract double calCost(ArrayList<CallRecord> callRecords);

}


abstract class ChargeRule {
    public abstract double calCost(ArrayList<CallRecord> callRecords);
}

class LandlinePhoneInCityRule extends CallChargeRule {
    @Override
    public double calCost(ArrayList<CallRecord> callRecords) {
        double price = 0;
        for (CallRecord callRecord : callRecords) {
            long datePoor = MyUtil.dateDiff(callRecord.getEndTime(), callRecord.getStartTime());
            price = price + datePoor * 0.1;
        }
        return price;
    }
}


class LandlinePhoneInLandRule extends CallChargeRule {
    @Override
    public double calCost(ArrayList<CallRecord> callRecords) {
        double price = 0;
        for (CallRecord callRecord : callRecords) {
            long datePoor = MyUtil.dateDiff(callRecord.getEndTime(), callRecord.getStartTime());
            price = price + datePoor * 0.6;
        }
        return price;
    }
}

class LandlinePhoneInProvinceRule extends CallChargeRule {
    @Override
    public double calCost(ArrayList<CallRecord> callRecords) {
        double price = 0;
        for (CallRecord callRecord : callRecords) {
            long datePoor = MyUtil.dateDiff(callRecord.getEndTime(), callRecord.getStartTime());
            price = price + datePoor * 0.3;
        }
        return price;
    }
}

class PhoneInLandCallingRule extends CallChargeRule {//省外长途0.6

    @Override
    public double calCost(ArrayList<CallRecord> callRecords) {
        double price = 0;
        for (CallRecord callRecord : callRecords) {
            long datePoor = MyUtil.dateDiff(callRecord.getEndTime(), callRecord.getStartTime());
            price = price + datePoor * 0.6;
        }
        return price;
    }
}


class PhoneInProvinceAnswerRule extends CallChargeRule {//接听0.3

    @Override
    public double calCost(ArrayList<CallRecord> callRecords) {
        double price = 0;
        for (CallRecord callRecord : callRecords) {
            long datePoor = MyUtil.dateDiff(callRecord.getEndTime(), callRecord.getStartTime());
            price = price + datePoor * 0.3;
        }
        return price;
    }
}


class PhoneInProvinceRule extends CallChargeRule {//省内0.2

    @Override
    public double calCost(ArrayList<CallRecord> callRecords) {
        double price = 0;
        for (CallRecord callRecord : callRecords) {
            long datePoor = MyUtil.dateDiff(callRecord.getEndTime(), callRecord.getStartTime());
            price = price + datePoor * 0.2;
        }
        return price;
    }
}


class User {
    private UserRecords userRecords = new UserRecords();
    private double balance = 100;
    private ChargeMode chargeMode;
    private String number;


    public double calBalance() {
        double price = 0;
        price += chargeMode.getMonthlyRent();
        return balance - price - calCost();
    }


    public double calCost() {
        return chargeMode.calCost(userRecords);
    }

    public double getBalance() {
        return balance;
    }

    public UserRecords getUserRecords() {
        return userRecords;
    }

    public void setUserRecords(UserRecords userRecords) {
        this.userRecords = userRecords;
    }

    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;
    }

}


class UserRecords {

    private ArrayList<CallRecord> callingInCityRecords = new ArrayList<>();//0.1

    private ArrayList<CallRecord> callingInProvinceRecords02 = new ArrayList<>();//0.2

    private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<>();//0.3

    private ArrayList<CallRecord> callingInLandRecords = new ArrayList<>();//0.6

    private ArrayList<CallRecord> answerInLandRecords = new ArrayList<>();//0.3


    private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<>();

    private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<>();

    public void addCallingInCityRecords(CallRecord callRecord) {
        callingInCityRecords.add(callRecord);
    }

    public void addCallingInProvinceRecords(CallRecord callRecord) {
        callingInProvinceRecords.add(callRecord);
    }

    public void addCallingInLandRecords(CallRecord callRecord) {
        callingInLandRecords.add(callRecord);
    }

    public void addAnswerInLandRecords(CallRecord callRecord) {
        answerInLandRecords.add(callRecord);
    }

    public void addSendMessageRecords(MessageRecord messageRecord) {
        sendMessageRecords.add(messageRecord);
    }

    public void addReceiveMessageRecords(MessageRecord messageRecord) {
        receiveMessageRecords.add(messageRecord);
    }

    public void addCallingInProvinceRecords02(CallRecord callRecord) {
        callingInProvinceRecords02.add(callRecord);
    }

    public ArrayList<CallRecord> getCallingInCityRecords() {
        return callingInCityRecords;
    }

    public ArrayList<CallRecord> getCallingInProvinceRecords() {
        return callingInProvinceRecords;
    }

    public ArrayList<CallRecord> getCallingInLandRecords() {
        return callingInLandRecords;
    }

    public ArrayList<CallRecord> getAnswerInLandRecords() {
        return answerInLandRecords;
    }

    public ArrayList<MessageRecord> getSendMessageRecords() {
        return sendMessageRecords;
    }

    public ArrayList<MessageRecord> getReceiveMessageRecords() {
        return receiveMessageRecords;
    }

    public ArrayList<CallRecord> getCallingInProvinceRecords02() {
        return callingInProvinceRecords02;
    }
}


class MyUtil {
    private MyUtil() {
    }

    public static Long dateDiff(Date startTime, Date endTime) {

        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        long ns = 1000;
        long diff;
        long day = 0;
        long hour = 0;
        long min = 0;
        long sec = 0;

        try {
            diff = startTime.getTime() - endTime.getTime();
            day = diff / nd;
            hour = diff % nd / nh + day * 24;
            min = diff % nd % nh / nm + day * 24 * 60;
            sec = diff % nd % nh % nm / ns;


        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        if (sec > 0) {
            min++;
        }
        return min;
    }


    public static String formatMoney(double money) {
        DecimalFormat df = new DecimalFormat("#0.0");
        return df.format(money); // 单位元;
    }
}

类图如下:

3.7-1 电信计费系列3-短信计费:

此题是第二题的改进版:总的来说就是实现发短信的功能。实现一个简单的电信计费程序,针对手机的短信采用如下计费方式:
1、接收短信免费,发送短信0.1元/条,超过3条0.2元/条,超过5条0.3元/条。
2、如果一次发送短信的字符数量超过10个,按每10个字符一条短信进行计算。

(1)首先跟前两题一样,判断用户数据,其次,需要注意短信的格式;短信内容只能由数字、字母、空格、英文逗号、英文句号组成。

private static boolean isPassPhone(String phoneNumber) throws Exception {
        if (phoneNumber.length() > 0 && !"1".equals(phoneNumber.substring(0, 1)))
            return false;
        return phoneNumber.length() == 11;
    }

    private static boolean isPassMessage(String message) throws Exception {
        for (char str : message.toCharArray()) {
            if (!isNumber(str) && !isZiMu(str) && str != ' ' && str != ',' && str != '.') {
                return false;
            }

        }
        return true;
    }

    private static boolean isNumber(char str) throws Exception {
        if (Character.isDigit(str)) {
            return true;
        } else {
            return false;
        }
    }

    private static boolean isZiMu(char str) throws Exception {
        if (((str >= 'a' && str <= 'z') || (str >= 'A' && str <= 'Z'))) {
            return true;
        } else {
            return false;
        }
    }
}

(2)增加MessageChargeRule类来进行判断短信的发送费用

class MessageChargeRule extends ChargeRule {
    @Override
    public double calCost(ArrayList<MessageRecord> callRecords) {
        double price = 0;
        long allMessageNum = 0;
        for (MessageRecord messageRecord : callRecords) {
            String message = messageRecord.getMessage();
            BigDecimal divide = new BigDecimal(message.length()).divide(new BigDecimal(10));
            long messageNum = divide.setScale(0, BigDecimal.ROUND_UP).longValue();
            allMessageNum += messageNum;
            if (allMessageNum <= 3 && allMessageNum > 0) {
                price = allMessageNum * 0.1;
            } else if (allMessageNum <= 5 && allMessageNum > 3) {
                price = 0.3 + (allMessageNum - 3) * 0.2;
            } else {
                price = 0.3 + 0.2 * 2 + (allMessageNum - 5) * 0.3;
            }

        }
        return price;
    }
}

完整代码如下:

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    private static Scanner scanner = new Scanner(System.in);
    private static ArrayList<User> users = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        // write your code here
        String code = " ";

        
            while (!((code = scanner.nextLine()).equals("end"))) {
                if (code.startsWith("u-")) {
                    handlerPhone(code);
                } else if (code.startsWith("m-")) {
                    handlerRecord(code);
                }
            }
            handlerPrint();
        

    }

    private static void handlerPrint() {
        Collections.sort(users, new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return o1.getNumber().compareTo(o2.getNumber());
            }
        });
        for (User user : users) {
            System.out.println(user.getNumber() + " " + MyUtil.formatMoney(user.calCost()) + " " + user.calBalance());
        }
    }

    private static void handlerRecord(String code) throws Exception {
        String[] dataList = code.split(" ");
        if (dataList.length < 3) {
            return;
        }
        String number = dataList[0].split("-")[1];
        String numberTwo = dataList[1];

        if (!isPassPhone(number) || !isPassPhone(numberTwo)) {
            return;
        }

        if (isExits(number)) {
            User user = getUser(number);
            String message = code.substring(charIndex(code, " ", 2) + 1);
            if (!isPassMessage(message)) {
                return;
            }
            MessageRecord messageRecord = new MessageRecord();
            messageRecord.setCallingNumber(number);
            messageRecord.setAnswerNumber(numberTwo);
            messageRecord.setMessage(message);

            user.getUserRecords().addSendMessageRecords(messageRecord);
        }

    }

    private static int charIndex(String str, String charStr, int position) {
        Pattern pattern = Pattern.compile(charStr);
        Matcher findMatcher = pattern.matcher(str);
        int number = 0;
        while (findMatcher.find()) {
            number++;
            if (number == position) {//当charStr第position次出现时中止
                break;
            }
        }
        int start = findMatcher.start();//“A”第二次出现的位置
        return start;
    }

    private static User getUser(String number) {
        for (User user : users) {
            if (user.getNumber().equals(number)) {
                return user;
            }
        }
        return null;
    }


    private static void handlerPhone(String code) throws Exception {
        String[] dataList = code.split(" ");
        String[] phoneList = dataList[0].split("-");
        String phoneNumber = phoneList[1];
        if (!isPassPhone(phoneNumber)) {
            return;
        }
        User user = null;

        if (isExits(phoneNumber)) {
            return;
        } else {
            user = new User();
            user.setNumber(phoneNumber);
            String type = dataList[1];
            if (type.equals("3")) {
                MessageCharging messageCharging = new MessageCharging();
                //创建用户时创建计费规则
                addChargeRules(messageCharging);
                user.setChargeMode(messageCharging);
            }
            users.add(user);
        }

    }

    private static void addChargeRules(ChargeMode chargeMode) {
        ArrayList<ChargeRule> chargeRules = chargeMode.getChargeRules();
        MessageChargeRule messageChargeRule = new MessageChargeRule();
        chargeRules.add(messageChargeRule);
    }

    private static boolean isExits(String phoneNumber) {
        for (User user : users) {
            if (user.getNumber().equals(phoneNumber)) {
                return true;
            }
        }
        return false;
    }

    private static boolean isPassPhone(String phoneNumber) throws Exception {
        if (phoneNumber.length() > 0 && !"1".equals(phoneNumber.substring(0, 1)))
            return false;
        return phoneNumber.length() == 11;
    }

    private static boolean isPassMessage(String message) throws Exception {
        for (char str : message.toCharArray()) {
            if (!isNumber(str) && !isZiMu(str) && str != ' ' && str != ',' && str != '.') {
                return false;
            }

        }
        return true;
    }

    private static boolean isNumber(char str) throws Exception {
        if (Character.isDigit(str)) {
            return true;
        } else {
            return false;
        }
    }

    private static boolean isZiMu(char str) throws Exception {
        if (((str >= 'a' && str <= 'z') || (str >= 'A' && str <= 'Z'))) {
            return true;
        } else {
            return false;
        }
    }
}

abstract class ChargeMode {
    private 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 MessageCharging extends ChargeMode {
    private double monthlyRent = 0;

    public double calCost(UserRecords userRecords) {
        double price = 0;

        for (ChargeRule chargeRule : getChargeRules()) {
            if (chargeRule instanceof MessageChargeRule) {
                price = price + chargeRule.calCost(userRecords.getSendMessageRecords());
            }
        }

        return price;
    }


    @Override
    public double getMonthlyRent() {

        return monthlyRent;
    }
}

abstract class CommunicationRecord {
    private String callingNumber;
    private 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 MessageRecord extends CommunicationRecord {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}


class MessageChargeRule extends ChargeRule {
    @Override
    public double calCost(ArrayList<MessageRecord> callRecords) {
        double price = 0;
        long allMessageNum = 0;
        for (MessageRecord messageRecord : callRecords) {
            String message = messageRecord.getMessage();
            BigDecimal divide = new BigDecimal(message.length()).divide(new BigDecimal(10));
            long messageNum = divide.setScale(0, BigDecimal.ROUND_UP).longValue();
            allMessageNum += messageNum;
            if (allMessageNum <= 3 && allMessageNum > 0) {
                price = allMessageNum * 0.1;
            } else if (allMessageNum <= 5 && allMessageNum > 3) {
                price = 0.3 + (allMessageNum - 3) * 0.2;
            } else {
                price = 0.3 + 0.2 * 2 + (allMessageNum - 5) * 0.3;
            }

        }
        return price;
    }
}


abstract class ChargeRule {
    public abstract double calCost(ArrayList<MessageRecord> callRecords);
}

class User {
    private UserRecords userRecords = new UserRecords();
    private double balance = 100;
    private ChargeMode chargeMode;
    private String number;


    public double calBalance() {
        double price = 0;
        price += chargeMode.getMonthlyRent();
        return balance - price - calCost();
    }


    public double calCost() {
        return chargeMode.calCost(userRecords);
    }

    public double getBalance() {
        return balance;
    }

    public UserRecords getUserRecords() {
        return userRecords;
    }

    public void setUserRecords(UserRecords userRecords) {
        this.userRecords = userRecords;
    }

    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;
    }

}


class UserRecords {

    private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<>();


    private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<>();


    public void addSendMessageRecords(MessageRecord messageRecord) {
        sendMessageRecords.add(messageRecord);
    }

    public void addReceiveMessageRecords(MessageRecord messageRecord) {
        receiveMessageRecords.add(messageRecord);
    }


    public ArrayList<MessageRecord> getSendMessageRecords() {
        return sendMessageRecords;
    }

    public ArrayList<MessageRecord> getReceiveMessageRecords() {
        return receiveMessageRecords;
    }

}


class MyUtil {
    private MyUtil() {
    }

    public static Long dateDiff(Date startTime, Date endTime) {

        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        long ns = 1000;
        long diff;
        long day = 0;
        long hour = 0;
        long min = 0;
        long sec = 0;

        try {
            diff = startTime.getTime() - endTime.getTime();
            day = diff / nd;
            hour = diff % nd / nh + day * 24;
            min = diff % nd % nh / nm + day * 24 * 60;
            sec = diff % nd % nh % nm / ns;


        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        if (sec > 0) {
            min++;
        }
        return min;
    }


    public static String formatMoney(double money) {
        DecimalFormat df = new DecimalFormat("#0.0");
        return df.format(money); // 单位元;
    }
}

类图如下:

三、采坑心得

1.7-1 电信计费系列1-座机计费

(1)前面提交的时候出现了编译错误,原因是没有去除public。

(2)在解决了编译错误这个问题后,以下的测试点还是出现了错误,经过测试,发现是判断的问题。有些不符合要求的没有筛除,这就导致了接下来的计算错误。

 

 

 

 

 

 

(3)将判断方法+正则表达式按照以下进行修改,只剩下最后一个错误:是粗心大意造成的。改正后本题目通过。

while (!((code = scanner.nextLine()).equals("end"))) {
if (code.startsWith("u-")) {
handlerPhone(code);
} else if (code.startsWith("t-")) {
String s = "t-(\\d){11,12}\\s(\\d){10,12}\\s((((1[6-9]|[2-9]\\d)\\d{2}).([13578]|1[02]).([1-9]|[12]\\d|3[01]))|(((1[6-9]|[2-9]\\d)\\d{2}).([13456789]|1[012]).([1-9]|[12]\\d|30))|(((1[6-9]|[2-9]\\d)\\d{2})-2-([1-9]|1\\d|2[0-8]))|(((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-2-29-)) (20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d\\s((((1[6-9]|[2-9]\\d)\\d{2}).([13578]|1[02]).([1-9]|[12]\\d|3[01]))|(((1[6-9]|[2-9]\\d)\\d{2}).([13456789]|1[012]).([1-9]|[12]\\d|30))|(((1[6-9]|[2-9]\\d)\\d{2})-2-([1-9]|1\\d|2[0-8]))|(((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-2-29-)) (20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d";

if(code.matches(s))
handlerRecord(code);
}
}
handlerPrint();

}

 

2.7-1 电信计费系列2-手机+座机计费

(1)在第一次提交后,几乎没什么正确的测试点,使用样例测试时发现只有个别的样例可以通过。

在寻求帮助后,发现是计算方法出现了问题,改正后的代码如下:

class PhoneCharging extends ChargeMode {
private double monthlyRent = 15;

@Override
public double calCost(UserRecords userRecords) {
double price = 0;

for (ChargeRule chargeRule : getChargeRules()) {

if (chargeRule instanceof LandlinePhoneInCityRule) {
price = price + chargeRule.calCost(userRecords.getCallingInCityRecords());
} else if (chargeRule instanceof LandlinePhoneInProvinceRule) {//市内拨省外、省内漫游0.3
price = price + chargeRule.calCost(userRecords.getCallingInProvinceRecords());
} else if (chargeRule instanceof PhoneInProvinceRule) {//市内拨市内0.2
price = price + chargeRule.calCost(userRecords.getCallingInProvinceRecords02());
} else if (chargeRule instanceof PhoneInProvinceAnswerRule) {//漫游接听0.3
ArrayList<CallRecord> answerInLandRecords = userRecords.getAnswerInLandRecords();
price = price + chargeRule.calCost(answerInLandRecords);
} else if (chargeRule instanceof LandlinePhoneInLandRule) {//省外长途0.6
price = price + chargeRule.calCost(userRecords.getCallingInLandRecords());
}
}
//todo

return price;
}


@Override
public double getMonthlyRent() {

return monthlyRent;
}
}

if (isExits(number)) {
User user = getUser(number);
UserRecords userRecords = user.getUserRecords();
if (answerCode.equals("0791") && callingCode.equals("0791")) {//市内拨打
userRecords.addCallingInCityRecords(callRecord);
} else if (isProvince(answerCode) && callingCode.equals("0791")) {//市内打省内
userRecords.addCallingInProvinceRecords02(callRecord);
} else if (!isProvince(answerCode) && !answerCode.equals("0791") && callingCode.equals("0791")) {//市内打省外
userRecords.addCallingInProvinceRecords(callRecord);
handlerAnswerPhone(answerCode, callRecord.getAnswerNumber(), callRecord);
} else if (!callingCode.equals("0791") && isProvince(callingCode)) {//省内漫游
userRecords.addCallingInProvinceRecords(callRecord);
handlerAnswerPhone(answerCode, callRecord.getAnswerNumber(), callRecord);
} else if (!callingCode.equals("0791") && !isProvince(callingCode)) {//省外漫游
userRecords.addCallingInLandRecords(callRecord);
handlerAnswerPhone(answerCode, callRecord.getAnswerNumber(), callRecord);
}
}

 (2)在改正计算方法后,以下的测试点还是出现了错误

 

经过测试后,发现是非法输入出现了问题,如果输入的电话太长,我的代码也是会输出,于是进行更改:

if (isExits(number)) {
User user = getUser(number);
String numberTwoPrefix = numberTwo.substring(0, 4);
String numberOnePrefix = number.substring(0, 4);

CallRecord callRecord = new CallRecord();
callRecord.setCallingNumber(number);
callRecord.setAnswerNumber(numberTwo);
callRecord.setAnswerAddressAreaCode(numberTwoPrefix);
callRecord.setCallingAddressAreaCode(numberOnePrefix);
callRecord.setStartTime(simpleDateFormat.parse(dataList[2] + " " + dataList[3]));
callRecord.setEndTime(simpleDateFormat.parse(dataList[4] + " " + dataList[5]));

if (numberTwoPrefix.equals("0791")) {
user.getUserRecords().addCallingInCityRecords(callRecord);
} else if (isProvince(numberTwoPrefix)) {
user.getUserRecords().addCallingInProvinceRecords(callRecord);
} else {
user.getUserRecords().addCallingInLandRecords(callRecord);
}
}
} else if (dataList.length == 7) {//座机手机互拨
if (isPassAreaNumber(dataList[2])) {//座机拨手机
String number = dataList[0].split("-")[1];
String numberOnePrefix = number.substring(0, 4);

if (!isPaseLandlinePhone2(number) || !isPassPhone(dataList[1])) {
return;
}

CallRecord callRecord = new CallRecord();
callRecord.setCallingNumber(number);
callRecord.setAnswerNumber(dataList[1]);
callRecord.setAnswerAddressAreaCode(dataList[2]);
callRecord.setCallingAddressAreaCode(numberOnePrefix);
callRecord.setStartTime(simpleDateFormat.parse(dataList[3] + " " + dataList[4]));
callRecord.setEndTime(simpleDateFormat.parse(dataList[5] + " " + dataList[6]));

if (isExits(number)) {
User user = getUser(number);
if (callRecord.getAnswerAddressAreaCode().equals("0791")) {//市内拨市内
user.getUserRecords().addCallingInCityRecords(callRecord);
} else if (isProvince(callRecord.getAnswerAddressAreaCode())) {//座机省内0.3
user.getUserRecords().addCallingInProvinceRecords(callRecord);
} else {//国际长途 0.6
user.getUserRecords().addCallingInLandRecords(callRecord);
//计算接电话的漫游
handlerAnswerPhone(callRecord.getAnswerAddressAreaCode(), callRecord.getAnswerNumber(), callRecord);
}
} else {//如果是漫游,手机接听要收费
//计算接电话的漫游
handlerAnswerPhone(callRecord.getAnswerAddressAreaCode(), callRecord.getAnswerNumber(), callRecord);
}
} else if (dataList[2].length() > 4) {//手机拨座机
String number = dataList[0].split("-")[1];

if (!isPaseLandlinePhone2(dataList[2]) || !isPassPhone(number)) {
return;
}

if (isExits(number)) {
User user = getUser(number);
CallRecord callRecord = new CallRecord();
callRecord.setCallingNumber(number);
callRecord.setAnswerNumber(dataList[2]);
callRecord.setAnswerAddressAreaCode(dataList[2].substring(0, 4));
callRecord.setCallingAddressAreaCode(dataList[1]);
callRecord.setStartTime(simpleDateFormat.parse(dataList[3] + " " + dataList[4]));
callRecord.setEndTime(simpleDateFormat.parse(dataList[5] + " " + dataList[6]));

这道题目最后我也没有全部完成,但是确实收获了许多
 
3.7-1 电信计费系列3-短信计费
(1)在第一提交后,以下出现了错误:
首先,没有判断加上空格正好是10位的情况,也没有判断十位全是空格的情况。
修改后的部分代码如下:

private static boolean isPassPhone(String phoneNumber) throws Exception {
if (phoneNumber.length() > 0 && !"1".equals(phoneNumber.substring(0, 1)))
return false;
return phoneNumber.length() == 11;
}

private static boolean isPassMessage(String message) throws Exception {
for (char str : message.toCharArray()) {
if (!isNumber(str) && !isZiMu(str) && str != ' ' && str != ',' && str != '.') {
return false;
}

}
return true;
}

private static boolean isNumber(char str) throws Exception {
if (Character.isDigit(str)) {
return true;
} else {
return false;
}
}

private static boolean isZiMu(char str) throws Exception {
if (((str >= 'a' && str <= 'z') || (str >= 'A' && str <= 'Z'))) {
return true;
} else {
return false;
}
}

 

(2)其次,在计算短信的费用时,一定要看清金额。

class MessageChargeRule extends ChargeRule {
@Override
public double calCost(ArrayList<MessageRecord> callRecords) {
double price = 0;
long allMessageNum = 0;
for (MessageRecord messageRecord : callRecords) {
String message = messageRecord.getMessage();
BigDecimal divide = new BigDecimal(message.length()).divide(new BigDecimal(10));
long messageNum = divide.setScale(0, BigDecimal.ROUND_UP).longValue();
allMessageNum += messageNum;
if (allMessageNum <= 3 && allMessageNum > 0) {
price = allMessageNum * 0.1;
} else if (allMessageNum <= 5 && allMessageNum > 3) {
price = 0.3 + (allMessageNum - 3) * 0.2;
} else {
price = 0.3 + 0.2 * 2 + (allMessageNum - 5) * 0.3;
}

}
return price;
}
}

四、改进建议

1、首先,这三道pta题目对本来java就不是很好的我来说难度很大,但我提升也很大,从一开始的只会使用列举法判断格式错误,到现在会用一点点正则表达式来判断格式错误;但是我的基础还不够好,有时思路不是很明确,总是来说就是缺少练习。

2.我最深的感受就是不知道如何去写,有时候写到一个部分,不知道该从哪里下手,也不知道该怎么写,感觉很迷茫,可能是缺少练习的原因吧。

3.从这几次的题目来看,我的代码有点乱而且比较长,有的时候我想到什么就会写什么,从而导致代码逻辑混乱,再出错时也找不到错误的原因,大大加长了消耗的时间。

4.所用的算法非常麻烦,有些题目是可以用到更简单的方法,有许多简单易懂的算法和思路,总的来说还是学会的东西太少,只会一些最最基础的代码,这一点还需要很大的提升。

5、可以通过类图来写出代码,通过类图,代码的难度减少了很多,类图方便易懂。

6、迭代的重要性:在这段时间里,我确实感受到了迭代的重要性,如果第一道题目思路清晰,写的比较完整,那么在这道题目的基础上进行改动就会简单许多。相反,如果一开始就写的很乱,那么之后的迭代只会更难,这点我深有体会。

五、总结

1.需要合理分配时间,java想要学好真的很难,需要付出很大的努力和时间,有pta,课堂练习,实验,mooc等等作业,所以不能把所有的放到最后一天写,更不要想着浑水摸鱼了,只有真正学到的才是自己的。

2.学会正则表达式的使用:https://www.runoob.com/java/java-regular-expressions.html,从这篇文章上真的学到了许多。

3.耦合:类与类之间关系的紧密程度---弱耦合性(有些时候理想情况为无耦合),内聚:类内---强内聚性

高内聚是另外一个评判软件设计质量的标准。内聚更为专业的说法叫做功能内聚,是对系统中元素职责的相关性和集中度的量度。
如果元素有高度的相关职责,除了这些职责在没有其他的工作,那么该元素就有高内聚。

4.注意迭代,一定要把代码的基础搞好。

 最后,我的代码基础不太好,写代码也不是很强,这也是本学期的最后一次blog,希望这个学期的java课程可以顺利通过。

 
 
 
posted @ 2022-06-16 21:01  Winter~  阅读(51)  评论(0)    收藏  举报