Daifff-

第三次博客作业

一、前言:

  • 这几个星期接触了电信计费的问题,这几次作业题量都相对来说不大,难度相对之前的点线形系列较低。
  • 通过这几次的题目集重新巩固了正则表达式,以及继承与多态的运用。
  • 第一次的题目集只要求写了座机计费,通过座机的区号判断所在位置,从而判断应该采用什么计费方式。
  • 第二次的题目集增加了手机计费,不仅需要判断计费方式,还要判断拨打与接听的是手机还是座机。
  • 第三次的题目集增加了短信计费,通过所在位置以及区号判断发短信价格。
  • 三道题目,联系十分紧密,迭代关系,第一道题的源码第二题第三题都能够直接用上,再按照要求修改。

 

 

二、设计与分析:

题目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
图1中User是用户类,包括属性:
userRecords (用户记录)、balance(余额)、chargeMode(计费方式)、number(号码)。

ChargeMode是计费方式的抽象类:
chargeRules是计费方式所包含的各种计费规则的集合,ChargeRule类的定义见图3。
getMonthlyRent()方法用于返回月租(monthlyRent)。

UserRecords是用户记录类,保存用户各种通话、短信的记录,    
各种计费规则将使用其中的部分或者全部记录。
其属性从上到下依次是:
市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、
市内接听电话、省内(不含市内)接听电话、省外接听电话的记录
以及发送短信、接收短信的记录。

                                     图2
图2中CommunicationRecord是抽象的通讯记录类:
包含callingNumber拨打号码、answerNumber接听号码两个属性。
CallRecord(通话记录)、MessageRecord(短信记录)是它的子类。

CallRecord(通话记录类)包含属性:
通话的起始、结束时间以及
拨号地点的区号(callingAddressAreaCode)、接听地点的区号(answerAddressAreaCode)。
区号用于记录在哪个地点拨打和接听的电话。座机无法移动,就是本机区号,如果是手机号,则会有差异。

 

                                        图3
图3是计费规则的相关类,这些类的核心方法是:
calCost(ArrayList<CallRecord> callRecords)。
该方法针根据输入参数callRecords中的所有记录计算某用户的某一项费用;如市话费。
输入参数callRecords的约束条件:必须是某一个用户的符合计费规则要求的所有记录。

LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是
座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。    
(提示:可以从UserRecords类中获取各种类型的callRecords)。

后续扩展说明:
后续题目集将增加手机用户,手机用户的计费方式中除了与座机计费类似的主叫通话费之外,还包含市外接听电话的漫游费以及发短信的费用。在本题的设计时可统一考虑。
通话记录中,手机需要额外记录拨打/接听的地点的区号,比如:
座机打手机: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
短信的格式:m-主叫号码,接收号码,短信内容
m-18907910010 13305862264 welcome to jiangxi
m-13305862264 18907910010 thank you

 

设计类图如下:

 

SourceMonitor报表如下:

代码如下:

code
import java.util.Scanner;
import java.util.TreeMap;
import java.util.ArrayList;
import java.util.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;

public class Main {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Scanner input = new Scanner(System.in);
		String a = input.nextLine();
		TreeMap<String, User> records = new TreeMap<String, User>();
		String checkU = "[u]-[0-9]{11,12}\\s[0,1,2]";
		String checkT = "t-\\d{11,12}\\s\\d{10,12}\\s\\d{4}.\\d{1,2}.\\d{1,2}\\s(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d\\s\\d{4}.\\d{1,2}.\\d{1,2}\\s(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d";
		while (!a.equals("end")) {
			if (a.matches(checkU)) {
				String[] array = a.substring(2).split(" ");
				String number = array[0].substring(4);
				ChargeMode mode = new LandlinePhoneCharging();
				User user = new User(number, mode);
				records.put(number, user);
			}
			if (a.matches(checkT)) {
				UserRecords userRecords = new UserRecords();
				String[] array = a.substring(2).split(" ");
				String callingAddressAreaCode = array[0].substring(0, 4);// 拨打电话地区
				String answerAddressAreaCode = array[1].substring(0, 4);// 接听电话地区
				String callingNumber = array[0].substring(4);// 拨打电话号码
				String answerNumber = array[1].substring(4);// 接听电话号码
				String startDate = array[2] + " " + array[3];// 开始时间
				String endDate = array[4] + " " + array[5];// 结束时间
				String[] m = array[2].split("\\.");
				int Month1 = Integer.parseInt(m[1]);
				int Year1 = Integer.parseInt(m[0]);
				int Day1 = Integer.parseInt(m[2]);
				String[] n = array[4].split("\\.");
				int Month2 = Integer.parseInt(n[1]);
				int Year2 = Integer.parseInt(n[0]);
				int Day2 = Integer.parseInt(n[2]);
				if (!checkInputValidity(Year1, Month1, Day1) || m[1].charAt(0) == '0' || n[1].charAt(0) == '0'
						|| !checkInputValidity(Year2, Month2, Day2)) {

				} else {
					Date startTime = new Date();
					Date endTime = new Date();
					SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
					try {
						startTime = format.parse(startDate);
						endTime = format.parse(endDate);
					} catch (ParseException e) {
						e.printStackTrace();
					}
					CallRecord callrecords = new CallRecord(callingNumber, answerNumber, startTime, endTime);
					if (records.get(callingNumber) != null) {
						if (callingAddressAreaCode.equals("0791") && answerAddressAreaCode.equals("0791")) {
							records.get(callingNumber).getUserRecords().addCallingCityRecords(callrecords);

						} else if ((callingAddressAreaCode.equals("0791") && answerAddressAreaCode.equals("0790"))
								|| (callingAddressAreaCode.equals("0791") && answerAddressAreaCode.equals("0792"))
								|| (callingAddressAreaCode.equals("0791") && answerAddressAreaCode.equals("0793"))
								|| (callingAddressAreaCode.equals("0791") && answerAddressAreaCode.equals("0794"))
								|| (callingAddressAreaCode.equals("0791") && answerAddressAreaCode.equals("0795"))
								|| (callingAddressAreaCode.equals("0791") && answerAddressAreaCode.equals("0796"))
								|| (callingAddressAreaCode.equals("0791") && answerAddressAreaCode.equals("0797"))
								|| (callingAddressAreaCode.equals("0791") && answerAddressAreaCode.equals("0798"))
								|| (callingAddressAreaCode.equals("0791") && answerAddressAreaCode.equals("0799"))
								|| (callingAddressAreaCode.equals("0791") && answerAddressAreaCode.equals("0701")))
							records.get(callingNumber).getUserRecords().addCallingProvinceRecords(callrecords);
						else
							records.get(callingNumber).getUserRecords().addCallingLandRecords(callrecords);
					}
				}
			}

			a = input.nextLine();
		}
		for (User user : records.values()) {

			System.out.println("0791" + user.getNumber() + " " + Math.round(user.calCost() * 100) / 100.0 + " "
					+ Math.round(user.calBalance() * 100) / 100.0);
		}

	}

	public static boolean checkInputValidity(int year, int month, int day) { // 判断输入数据是否合法
		if (month < 1 || month > 12)
			return false;
		else if (day < 1 || day > 31)
			return false;
		else if ((month == 4 && day >= 31) || (month == 6 && day >= 31) || (month == 9 && day >= 31)
				|| (month == 11 && day >= 31))
			return false;
		else if (month == 2 && isLeapYear(year) == true && day > 29)
			return false;
		else if (month == 2 && isLeapYear(year) == false && day > 28)
			return false;
		else
			return true;
	}

	public static boolean isLeapYear(int year) { // 判断是否为闰年
		if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
			return true;
		else
			return false;
	}

}




 class MessageRecord extends CommunicationRecord {
	String message;

	public String getMessage() {
		return message;
	}

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

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

	public User(String number, ChargeMode mode) {
		// TODO 自动生成的构造函数存根
		this.number = number;
		this.chargeMode = mode;
	}

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

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

	public UserRecords getUserRecords() {
		return userRecords;
	}

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

	public double getBalance() {
		return balance;
	}

	public void setBalance(double balance) {
		this.balance = balance;
	}

	public ChargeMode getChargeMode() {
		return chargeMode;
	}

	public void setChargeMode(ChargeMode chargeMode) {
		this.chargeMode = chargeMode;
	}

	public String getNumber() {
		return number;
	}

	public void setNumber(String number) {
		this.number = number;
	}

}
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> sendMessageRecords = new ArrayList<MessageRecord>();
	ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<MessageRecord>();

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

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

	public void addCallingLandRecords(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 addSendMessageRecords(MessageRecord sendMessageRecord) {
		sendMessageRecords.add(sendMessageRecord);
	}

	public void addReceiveMessageRecords(MessageRecord receiveMessageRecord) {
		receiveMessageRecords.add(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;
	}

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

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

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

}
class CallRecord extends CommunicationRecord{
	Date startTime;
	Date endTime;
	String callingAddressAreaCode;
	String answerAddressAreaCode;
	String callingNumber;
	String answerNumber;
	

	public CallRecord(String callingNumber, String answerNumber, Date startTime, Date endTime) {
		// TODO 自动生成的构造函数存根
		this.callingNumber = callingNumber;
		this.answerNumber = answerNumber;
		this.startTime = startTime;
		this.endTime = endTime;
	}

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

}
abstract class ChargeMode {
	ArrayList<ChargeRule> chargeRules = new ArrayList<ChargeRule>();

	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();

}
abstract class ChargeRule {

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

//	public abstract double CalCost(ArrayList<CallRecord> answerInCityRecords);

}
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;
	}
}
class LandlinePhoneCharging extends ChargeMode {
	double montlyRent = 20;

	public LandlinePhoneCharging() {
		super();
		// TODO 自动生成的构造函数存根
	}

	
	public double calCost(UserRecords userRecords) {
		getChargeRules().add(new LandPhoneInCityRule());
		getChargeRules().add(new LandPhoneInProvinceRule());
		getChargeRules().add(new LandPhoneInLandRule());
		double sum = 0;
		sum = super.getChargeRules().get(0).calCost(userRecords.getCallingInCityRecords())
				+ super.getChargeRules().get(1).calCost(userRecords.getCallingInProvinceRecords())
				+ super.getChargeRules().get(2).calCost(userRecords.getCallingInLandRecords());
		return sum;
	}



	@Override
	public double getMonthlyRent() {
		// TODO 自动生成的方法存根
		return this.montlyRent;
	}



}
class LandPhoneInCityRule extends CallChargeRule {

	public double calCost(ArrayList<CallRecord> callRecords) {
		double sum = 0;
		for(CallRecord a:callRecords)
		sum = sum + Math.ceil((a.getEndTime().getTime() - a.getStartTime().getTime()) / 1000.0 / 60.0);
		sum = sum * 0.1;
		return sum;
	}



	
	

}
class LandPhoneInLandRule extends CallChargeRule {


	

	@Override
	public double calCost(ArrayList<CallRecord> callRecords) {
		// TODO 自动生成的方法存根
		double sum = 0;
		for(CallRecord a:callRecords)
		sum = sum + Math.ceil((a.getEndTime().getTime() - a.getStartTime().getTime()) / 1000.0 / 60.0);
		sum = sum * 0.6;
		return sum;
	}

	

	

}
class LandPhoneInProvinceRule extends CallChargeRule {
	public double calCost(ArrayList<CallRecord> callRecords) {
		double sum = 0;
		for(CallRecord a:callRecords)
		sum = sum + Math.ceil((a.getEndTime().getTime() - a.getStartTime().getTime()) / 1000.0 / 60.0);
		sum = sum * 0.3;
		return sum;
	}

	

	
	
}

 

分析:

  • 在根据所给部分类图提示下,将类间关系较快的整理清楚,并且搭建好了框架,不知道自己在没有给类图的情况下,自己并不能这么快的完成这份工作。
  • 这道题主要考察正则表达式的应用,通过正则表达式将输入数据中出现的不符合格式要求的行一律忽略,并且判断是开户还是拨打电话。
  • 考察了字符串的截取,灵活的运用substring以及split方法将开户电话号码、拨打电话号码、接听电话号码、拨打电话区号、接听电话区号、开始时间以及结束时间分别截取出来。
  • 在截取出所需信息后,首先判断日期以及时间是否合理,我通过之前所写过的方法,将其附用在本题上,其次通过区号判断计费方式。

 

踩坑心得:

  • 在前几次提交代码一直都只有49分,由于正则表达式的错误,导致一直没有忽略异常数据,导致代码不完善,我通过debug才找出这个问题,先输入一个错误数据,然后进行单步跳入,结果发现错误数据仍然能够进入开户或者打电话这一步,于是我重新检查正则表达式,并未没有发现错误,这样反反复复浪费了很长时间,最后将正则表达式全部删去,重新写了一遍,考虑的更全面,最终正确。
  • 在修改完正则后,分数达到了54分,我思考了很久也没有想到原因,于是我又进行了很多数据的测试,以及debug,发现并没有错误,最后在同学的提示下,发现了没有开户的号码不能用来打电话,于是在拨打电话增加此号码通话记录之前添加了拨打号码不能为空的条件,最终结果正确。

 

 

题目2).

电信计费系列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元。
每条通讯、短信信息均单独计费后累加,不是将所有信息累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略。

本题只做格式的错误判断,无需做内容上不合理的判断,比如同一个电话两条通讯记录的时间有重合、开户号码非南昌市的号码等,此类情况都当成正确的输入计算。但时间的输入必须符合要求,比如不能输入2022.13.61 28:72:65。

 

设计类图如下:

 

SourceMonitor报表如下:

 

代码如下:

code
import java.util.Scanner;
import java.util.TreeMap;
import java.util.ArrayList;
import java.util.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;

public class Main {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Scanner input = new Scanner(System.in);
		String a = input.nextLine();
		TreeMap<String, User> records = new TreeMap<String, User>();
		String checkUlandline = "u-0\\d{9,11}\\s0";
		String checkUphone = "u-1\\d{10}\\s1";
		String checkTlandlineTolandline = "t-0\\d{9,11}\\s0\\d{9,11}\\s\\d{4}.\\d{1,2}.\\d{1,2}\\s(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d\\s\\d{4}.\\d{1,2}.\\d{1,2}\\s(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d";
		String checkTlandlineTophone = "t-0\\d{9,11}\\s1\\d{10}\\s0\\d{2,3}\\s\\d{4}.\\d{1,2}.\\d{1,2}\\s(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d\\s\\d{4}.\\d{1,2}.\\d{1,2}\\s(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d";
		String checkTphoneTophone = "t-1\\d{10}\\s0\\d{2,3}\\s1\\d{10}\\s0\\d{2,3}\\s\\d{4}.\\d{1,2}.\\d{1,2}\\s(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d\\s\\d{4}.\\d{1,2}.\\d{1,2}\\s(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d";
		String checkTphoneTolandline = "t-1\\d{10}\\s0\\d{2,3}\\s0\\d{2,3}\\d{7,8}\\s\\d{4}.\\d{1,2}.\\d{1,2}\\s(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d\\s\\d{4}.\\d{1,2}.\\d{1,2}\\s(0\\d|1\\d|2[0-3]):[0-5]\\d:[0-5]\\d";
		while (!a.equals("end")) {
			if (a.matches(checkUlandline)) {
				String[] array = a.substring(2).split(" ");
				String number = array[0];
				LandlinePhoneCharging mode = new LandlinePhoneCharging();// 你开户想要的套餐
				User user = new User(number, mode);// 开户 并且将你开户的号码与套餐传进用户里
				records.put(number, user);// 将这个用户信息传到这个容器里
			}

			if (a.matches(checkUphone)) {
				String[] array = a.substring(2).split(" ");
				String number = array[0];
				CellphoneCharging mode = new CellphoneCharging();
				User user = new User(number, mode);// 开户 并且将你开户的号码与套餐传进用户里
				records.put(number, user);// 将这个用户信息传到这个容器里
			}
			if (a.matches(checkTphoneTolandline)) { // 手机打座机
				String[] array = a.substring(2).split(" ");
				String callingAddressAreaCode = array[1];
				String answerAddressAreaCode = array[2].substring(0, 4);
				String callingNumber = array[0];// 拨打电话号码
				String answerNumber = array[2];// 接听电话号码
				String startDate = array[3] + " " + array[4];// 开始时间
				String endDate = array[5] + " " + array[6];// 结束时间
				String[] m = array[3].split("\\.");
				int Month1 = Integer.parseInt(m[1]);
				int Year1 = Integer.parseInt(m[0]);
				int Day1 = Integer.parseInt(m[2]);
				String[] n = array[5].split("\\.");
				int Month2 = Integer.parseInt(n[1]);
				int Year2 = Integer.parseInt(n[0]);
				int Day2 = Integer.parseInt(n[2]);
				if (!checkInputValidity(Year1, Month1, Day1) || m[1].charAt(0) == '0' || n[1].charAt(0) == '0'
						|| !checkInputValidity(Year2, Month2, Day2)) {

				} else {
					Date startTime = new Date();
					Date endTime = new Date();
					SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
					try {
						startTime = format.parse(startDate);
						endTime = format.parse(endDate);
					} catch (ParseException e) {
						e.printStackTrace();
					}
					CallRecord callrecords = new CallRecord(callingNumber, answerNumber, startTime, endTime,
							callingAddressAreaCode, answerAddressAreaCode);

					if (answerAddressAreaCode.equals("0791")) {
						if (records.get(callingNumber) != null)
							records.get(callingNumber).getUserRecords().addCallingCityRecords(callrecords);
						if (records.get(answerNumber) != null)
							records.get(answerNumber).getUserRecords().addAnswerInCityRecords(callrecords);

					} else if (answerAddressAreaCode.equals("0790") || answerAddressAreaCode.equals("0792")
							|| answerAddressAreaCode.equals("0793") || answerAddressAreaCode.equals("0794")
							|| answerAddressAreaCode.equals("0795") || answerAddressAreaCode.equals("0796")
							|| answerAddressAreaCode.equals("0797") || answerAddressAreaCode.equals("0798")
							|| answerAddressAreaCode.equals("0799") || answerAddressAreaCode.equals("0701")) {
						if (records.get(callingNumber) != null)
							records.get(callingNumber).getUserRecords().addCallingProvinceRecords(callrecords);
						if (records.get(answerNumber) != null)
							records.get(answerNumber).getUserRecords().addAnswerInProvinceRecords(callrecords);
					} else {
						if (records.get(callingNumber) != null)
							records.get(callingNumber).getUserRecords().addCallingLandRecords(callrecords);
						if (records.get(answerNumber) != null)
							records.get(answerNumber).getUserRecords().addAnswerInLandRecords(callrecords);
					}

				}
			} // 手机打座机
			if (a.matches(checkTphoneTophone)) { // 手机打手机
				String[] array = a.substring(2).split(" ");
				String callingAddressAreaCode = array[1];
				String answerAddressAreaCode = array[3];
				String callingNumber = array[0];// 拨打电话号码
				String answerNumber = array[2];// 接听电话号码
				String startDate = array[4] + " " + array[5];// 开始时间
				String endDate = array[6] + " " + array[7];// 结束时间
				CellphoneCharging mode = new CellphoneCharging();
//				User user = new User(answerNumber, mode);// 开户 并且将你开户的号码与套餐传进用户里
//				records.put(answerNumber, user);// 将这个用户信息传到这个容器里
				String[] m = array[4].split("\\.");
				int Month1 = Integer.parseInt(m[1]);
				int Year1 = Integer.parseInt(m[0]);
				int Day1 = Integer.parseInt(m[2]);
				String[] n = array[6].split("\\.");
				int Month2 = Integer.parseInt(n[1]);
				int Year2 = Integer.parseInt(n[0]);
				int Day2 = Integer.parseInt(n[2]);
				if (!checkInputValidity(Year1, Month1, Day1) || m[1].charAt(0) == '0' || n[1].charAt(0) == '0'
						|| !checkInputValidity(Year2, Month2, Day2)) {

				} else {
					Date startTime = new Date();
					Date endTime = new Date();
					SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
					try {
						startTime = format.parse(startDate);
						endTime = format.parse(endDate);
					} catch (ParseException e) {
						e.printStackTrace();
					}
					CallRecord callrecords = new CallRecord(callingNumber, answerNumber, startTime, endTime,
							callingAddressAreaCode, answerAddressAreaCode);

					if (answerAddressAreaCode.equals("0791")) {
						if (records.get(callingNumber) != null)
							records.get(callingNumber).getUserRecords().addCallingCityRecords(callrecords);
						if (records.get(answerNumber) != null)
							records.get(answerNumber).getUserRecords().addAnswerInCityRecords(callrecords);

					} else if (answerAddressAreaCode.equals("0790") || answerAddressAreaCode.equals("0792")
							|| answerAddressAreaCode.equals("0793") || answerAddressAreaCode.equals("0794")
							|| answerAddressAreaCode.equals("0795") || answerAddressAreaCode.equals("0796")
							|| answerAddressAreaCode.equals("0797") || answerAddressAreaCode.equals("0798")
							|| answerAddressAreaCode.equals("0799") || answerAddressAreaCode.equals("0701")) {
						if (records.get(callingNumber) != null)
							records.get(callingNumber).getUserRecords().addCallingProvinceRecords(callrecords);
						if (records.get(answerNumber) != null)
							records.get(answerNumber).getUserRecords().addAnswerInProvinceRecords(callrecords);
					} else {
						if (records.get(callingNumber) != null)
							records.get(callingNumber).getUserRecords().addCallingLandRecords(callrecords);
						if (records.get(answerNumber) != null)
							records.get(answerNumber).getUserRecords().addAnswerInLandRecords(callrecords);
					}

				}
			}

			if (a.matches(checkTlandlineTophone)) { // 座机打手机
				String[] array = a.substring(2).split(" ");
				String callingAddressAreaCode = array[0].substring(0, 4);// 拨打电话地区
				String answerAddressAreaCode = array[2];// 接听电话地区
				String callingNumber = array[0];// 拨打电话号码
				String answerNumber = array[1];// 接听电话号码
				String startDate = array[3] + " " + array[4];// 开始时间
				String endDate = array[5] + " " + array[6];// 结束时间
				String[] m = array[3].split("\\.");
				int Month1 = Integer.parseInt(m[1]);
				int Year1 = Integer.parseInt(m[0]);
				int Day1 = Integer.parseInt(m[2]);
				String[] n = array[5].split("\\.");
				int Month2 = Integer.parseInt(n[1]);
				int Year2 = Integer.parseInt(n[0]);
				int Day2 = Integer.parseInt(n[2]);
				if (!checkInputValidity(Year1, Month1, Day1) || m[1].charAt(0) == '0' || n[1].charAt(0) == '0'
						|| !checkInputValidity(Year2, Month2, Day2)) {

				} else {
					Date startTime = new Date();
					Date endTime = new Date();
					SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
					try {
						startTime = format.parse(startDate);
						endTime = format.parse(endDate);
					} catch (ParseException e) {
						e.printStackTrace();
					}
					CallRecord callrecords = new CallRecord(callingNumber, answerNumber, startTime, endTime,
							callingAddressAreaCode, answerAddressAreaCode);

					if (answerAddressAreaCode.equals("0791")) {
						if (records.get(callingNumber) != null)
							records.get(callingNumber).getUserRecords().addCallingCityRecords(callrecords);
						if (records.get(answerNumber) != null)
							records.get(answerNumber).getUserRecords().addAnswerInCityRecords(callrecords);

					} else if (answerAddressAreaCode.equals("0790") || answerAddressAreaCode.equals("0792")
							|| answerAddressAreaCode.equals("0793") || answerAddressAreaCode.equals("0794")
							|| answerAddressAreaCode.equals("0795") || answerAddressAreaCode.equals("0796")
							|| answerAddressAreaCode.equals("0797") || answerAddressAreaCode.equals("0798")
							|| answerAddressAreaCode.equals("0799") || answerAddressAreaCode.equals("0701")) {
						if (records.get(callingNumber) != null)
							records.get(callingNumber).getUserRecords().addCallingProvinceRecords(callrecords);
						if (records.get(answerNumber) != null)
							records.get(answerNumber).getUserRecords().addAnswerInProvinceRecords(callrecords);
					} else {
						if (records.get(callingNumber) != null)
							records.get(callingNumber).getUserRecords().addCallingLandRecords(callrecords);
						if (records.get(answerNumber) != null)
							records.get(answerNumber).getUserRecords().addAnswerInLandRecords(callrecords);
					}

				}
			} // 座机打手机

			if (a.matches(checkTlandlineTolandline)) { // 座机打座机
				String[] array = a.substring(2).split(" ");
				String callingAddressAreaCode = array[0].substring(0, 4);// 拨打电话地区
				String answerAddressAreaCode = array[1].substring(0, 4);// 接听电话地区
				String callingNumber = array[0];// 拨打电话号码
				String answerNumber = array[1];// 接听电话号码
				String startDate = array[2] + " " + array[3];// 开始时间
				String endDate = array[4] + " " + array[5];// 结束时间
				String[] m = array[2].split("\\.");
				int Month1 = Integer.parseInt(m[1]);
				int Year1 = Integer.parseInt(m[0]);
				int Day1 = Integer.parseInt(m[2]);
				String[] n = array[4].split("\\.");
				int Month2 = Integer.parseInt(n[1]);
				int Year2 = Integer.parseInt(n[0]);
				int Day2 = Integer.parseInt(n[2]);
				if (!checkInputValidity(Year1, Month1, Day1) || m[1].charAt(0) == '0' || n[1].charAt(0) == '0'
						|| !checkInputValidity(Year2, Month2, Day2)) {

				} else {
					Date startTime = new Date();
					Date endTime = new Date();
					SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
					try {
						startTime = format.parse(startDate);
						endTime = format.parse(endDate);
					} catch (ParseException e) {
						e.printStackTrace();
					}
					CallRecord callrecords = new CallRecord(callingNumber, answerNumber, startTime, endTime,
							callingAddressAreaCode, answerAddressAreaCode);

					if (answerAddressAreaCode.equals("0791")) {
						if (records.get(callingNumber) != null)
							records.get(callingNumber).getUserRecords().addCallingCityRecords(callrecords);
						if (records.get(answerNumber) != null)
							records.get(answerNumber).getUserRecords().addAnswerInCityRecords(callrecords);

					} else if (answerAddressAreaCode.equals("0790") || answerAddressAreaCode.equals("0792")
							|| answerAddressAreaCode.equals("0793") || answerAddressAreaCode.equals("0794")
							|| answerAddressAreaCode.equals("0795") || answerAddressAreaCode.equals("0796")
							|| answerAddressAreaCode.equals("0797") || answerAddressAreaCode.equals("0798")
							|| answerAddressAreaCode.equals("0799") || answerAddressAreaCode.equals("0701")) {
						if (records.get(callingNumber) != null)
							records.get(callingNumber).getUserRecords().addCallingProvinceRecords(callrecords);
						if (records.get(answerNumber) != null)
							records.get(answerNumber).getUserRecords().addAnswerInProvinceRecords(callrecords);
					} else {
						if (records.get(callingNumber) != null)
							records.get(callingNumber).getUserRecords().addCallingLandRecords(callrecords);
						if (records.get(answerNumber) != null)
							records.get(answerNumber).getUserRecords().addAnswerInLandRecords(callrecords);
					}
				}
			}
			// 座机打座机

			a = input.nextLine();
		}
		for (User user : records.values()) {
			System.out.println(user.getNumber() + " " + Math.round(user.calCost() * 100) / 100.0 + " "
					+ Math.round(user.calBalance() * 100) / 100.0);
		}

	}

	public static boolean checkInputValidity(int year, int month, int day) { // 判断输入数据是否合法
		if (month < 1 || month > 12)
			return false;
		else if (day < 1 || day > 31)
			return false;
		else if ((month == 4 && day >= 31) || (month == 6 && day >= 31) || (month == 9 && day >= 31)
				|| (month == 11 && day >= 31))
			return false;
		else if (month == 2 && isLeapYear(year) == true && day > 29)
			return false;
		else if (month == 2 && isLeapYear(year) == false && day > 28)
			return false;
		else
			return true;
	}

	public static boolean isLeapYear(int year) { // 判断是否为闰年
		if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
			return true;
		else
			return false;
	}

}
abstract class MessageChargeRule extends ChargeRule {
//	public abstract double calCost(ArrayList<MessageRecord> messageRecords);
}
class MessageRecord extends CommunicationRecord {
	String message;

	public String getMessage() {
		return message;
	}

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

}


class SendMessageRule extends MessageChargeRule{

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





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

	public User(String number, ChargeMode mode) {
		// TODO 自动生成的构造函数存根
		this.number = number;
		this.chargeMode = mode;
	}

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

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

	public UserRecords getUserRecords() {
		return userRecords;
	}

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

	public double getBalance() {
		return balance;
	}

	public void setBalance(double balance) {
		this.balance = balance;
	}

	public ChargeMode getChargeMode() {
		return chargeMode;
	}

	public void setChargeMode(ChargeMode chargeMode) {
		this.chargeMode = chargeMode;
	}

	public String getNumber() {
		return number;
	}

	public void setNumber(String number) {
		this.number = number;
	}

}
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> sendMessageRecords = new ArrayList<MessageRecord>();
	ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<MessageRecord>();

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

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

	public void addCallingLandRecords(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 addSendMessageRecords(MessageRecord sendMessageRecord) {
		sendMessageRecords.add(sendMessageRecord);
	}

	public void addReceiveMessageRecords(MessageRecord receiveMessageRecord) {
		receiveMessageRecords.add(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;
	}

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

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

}
class AnswerInLandRule extends CallChargeRule {

	@Override
	public double calCost(ArrayList<CallRecord> callRecords) {
		// TODO 自动生成的方法存根
		double sum = 0;
		for (CallRecord a : callRecords) {
			sum = sum + Math.ceil((a.getEndTime().getTime() - a.getStartTime().getTime()) / 1000.0 / 60.0);
		}
		sum = sum * 0.3;
		return sum;
	}

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

}
class CallRecord extends CommunicationRecord {
	Date startTime;
	Date endTime;
	String callingAddressAreaCode;
	String answerAddressAreaCode;
	String callingNumber;
	String answerNumber;

	public CallRecord(String callingNumber, String answerNumber, Date startTime, Date endTime,
			String callingAddressAreaCode, String answerAddressAreaCode) {
		// TODO 自动生成的构造函数存根
		this.callingNumber = callingNumber;
		this.answerNumber = answerNumber;
		this.startTime = startTime;
		this.endTime = endTime;
		this.callingAddressAreaCode = callingAddressAreaCode;
		this.answerAddressAreaCode = 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;
	}

}
 class CellphoneCharging extends ChargeMode {
	double montlyRent = 15;

	@Override
	public double calCost(UserRecords userRecords) {
		// TODO 自动生成的方法存根
		getChargeRules().add(new CellPhoneInCityRule());
		getChargeRules().add(new CellPhoneInProvinceRule());
		getChargeRules().add(new CellPhoneInLandRule());
		getChargeRules().add(new AnswerInLandRule());
		double sum = 0;
		sum = super.getChargeRules().get(0).calCost(userRecords.getCallingInCityRecords())
				+ super.getChargeRules().get(1).calCost(userRecords.getCallingInProvinceRecords())
				+ super.getChargeRules().get(2).calCost(userRecords.getCallingInLandRecords())
				+ super.getChargeRules().get(3).calCost(userRecords.getAnswerInLandRecords());
		return sum;
	}

	@Override
	public double getMonthlyRent() {
		// TODO 自动生成的方法存根
		return montlyRent;
	}

}
class CellPhoneInCityRule extends CallChargeRule {

	public double calCost(ArrayList<CallRecord> callRecords) {
		double sum = 0;
		for (CallRecord a : callRecords) {
			
			if (a.getCallingAddressAreaCode().equals("0791")) {
				sum = sum + Math.ceil((a.getEndTime().getTime() - a.getStartTime().getTime()) / 1000.0 / 60.0)* 0.1;
			
			}
			if (a.getCallingAddressAreaCode().equals("0790") || a.getCallingAddressAreaCode().equals("0792")
					|| a.getCallingAddressAreaCode().equals("0793") || a.getCallingAddressAreaCode().equals("0794")
					|| a.getCallingAddressAreaCode().equals("0795") || a.getCallingAddressAreaCode().equals("0796")
					|| a.getCallingAddressAreaCode().equals("0797") || a.getCallingAddressAreaCode().equals("0798")
					|| a.getCallingAddressAreaCode().equals("0799") || a.getCallingAddressAreaCode().equals("0701")) {
				sum = sum + Math.ceil((a.getEndTime().getTime() - a.getStartTime().getTime()) / 1000.0 / 60.0)* 0.3;
			
			}
			if (!a.getCallingAddressAreaCode().equals("0790") && !a.getCallingAddressAreaCode().equals("0791")
					&& !a.getCallingAddressAreaCode().equals("0792") && !a.getCallingAddressAreaCode().equals("0793")
					&& !a.getCallingAddressAreaCode().equals("0794") && !a.getCallingAddressAreaCode().equals("0795")
					&& !a.getCallingAddressAreaCode().equals("0796") && !a.getCallingAddressAreaCode().equals("0797")
					&& !a.getCallingAddressAreaCode().equals("0798") && !a.getCallingAddressAreaCode().equals("0799")
					&& !a.getCallingAddressAreaCode().equals("0701")) {
				sum = sum + Math.ceil((a.getEndTime().getTime() - a.getStartTime().getTime()) / 1000.0 / 60.0)* 0.6;

			}
		}
		return sum;
	}
}

class CellPhoneInLandRule extends CallChargeRule {

	public double calCost(ArrayList<CallRecord> callRecords) {
		double sum = 0;
		for (CallRecord a : callRecords) {
			if (a.getCallingAddressAreaCode().equals("0791")) {
				sum = sum + Math.ceil((a.getEndTime().getTime() - a.getStartTime().getTime()) / 1000.0 / 60.0)* 0.3;
	
			}
			if (a.getCallingAddressAreaCode().equals("0790") || a.getCallingAddressAreaCode().equals("0792")
					|| a.getCallingAddressAreaCode().equals("0793") || a.getCallingAddressAreaCode().equals("0794")
					|| a.getCallingAddressAreaCode().equals("0795") || a.getCallingAddressAreaCode().equals("0796")
					|| a.getCallingAddressAreaCode().equals("0797") || a.getCallingAddressAreaCode().equals("0798")
					|| a.getCallingAddressAreaCode().equals("0799") || a.getCallingAddressAreaCode().equals("0701")) {
				sum = sum + Math.ceil((a.getEndTime().getTime() - a.getStartTime().getTime()) / 1000.0 / 60.0)* 0.3;
		
			}
			if (!a.getCallingAddressAreaCode().equals("0790") && !a.getCallingAddressAreaCode().equals("0791")
					&& !a.getCallingAddressAreaCode().equals("0792") && !a.getCallingAddressAreaCode().equals("0793")
					&& !a.getCallingAddressAreaCode().equals("0794") && !a.getCallingAddressAreaCode().equals("0795")
					&& !a.getCallingAddressAreaCode().equals("0796") && !a.getCallingAddressAreaCode().equals("0797")
					&& !a.getCallingAddressAreaCode().equals("0798") && !a.getCallingAddressAreaCode().equals("0799")
					&& !a.getCallingAddressAreaCode().equals("0701")) {
				sum = sum + Math.ceil((a.getEndTime().getTime() - a.getStartTime().getTime()) / 1000.0 / 60.0)* 0.6;
			}
		}

		return sum;
	}

}

class CellPhoneInProvinceRule extends CallChargeRule {
	public double calCost(ArrayList<CallRecord> callRecords) {
		double sum = 0;
		for (CallRecord a : callRecords) {
			if (a.getCallingAddressAreaCode().equals("0791")) {
				sum = sum + Math.ceil((a.getEndTime().getTime() - a.getStartTime().getTime()) / 1000.0 / 60.0) * 0.2;

			}
			if (a.getCallingAddressAreaCode().equals("0790") || a.getCallingAddressAreaCode().equals("0792")
					|| a.getCallingAddressAreaCode().equals("0793") || a.getCallingAddressAreaCode().equals("0794")
					|| a.getCallingAddressAreaCode().equals("0795") || a.getCallingAddressAreaCode().equals("0796")
					|| a.getCallingAddressAreaCode().equals("0797") || a.getCallingAddressAreaCode().equals("0798")
					|| a.getCallingAddressAreaCode().equals("0799") || a.getCallingAddressAreaCode().equals("0701")) {
				sum = sum + Math.ceil((a.getEndTime().getTime() - a.getStartTime().getTime()) / 1000.0 / 60.0)* 0.3;
	
			}
			if (!a.getCallingAddressAreaCode().equals("0790") && !a.getCallingAddressAreaCode().equals("0791")
					&& !a.getCallingAddressAreaCode().equals("0792") && !a.getCallingAddressAreaCode().equals("0793")
					&& !a.getCallingAddressAreaCode().equals("0794") && !a.getCallingAddressAreaCode().equals("0795")
					&& !a.getCallingAddressAreaCode().equals("0796") && !a.getCallingAddressAreaCode().equals("0797")
					&& !a.getCallingAddressAreaCode().equals("0798") && !a.getCallingAddressAreaCode().equals("0799")
					&& !a.getCallingAddressAreaCode().equals("0701")) {
				sum = sum + Math.ceil((a.getEndTime().getTime() - a.getStartTime().getTime()) / 1000.0 / 60.0)* 0.6;

			}
		}
		return sum;
	}
}

 abstract class ChargeMode {
	ArrayList<ChargeRule> chargeRules = new ArrayList<ChargeRule>();

	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();

}
abstract class ChargeRule {

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

//	public abstract double CalCost(ArrayList<CallRecord> answerInCityRecords);

}
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;
	}
}
class LandlinePhoneCharging extends ChargeMode {
	double montlyRent = 20;

	public LandlinePhoneCharging() {
		super();
		// TODO 自动生成的构造函数存根
	}

	public double calCost(UserRecords userRecords) {
		getChargeRules().add(new LandPhoneInCityRule());
		getChargeRules().add(new LandPhoneInProvinceRule());
		getChargeRules().add(new LandPhoneInLandRule());
		double sum = 0;
		sum = super.getChargeRules().get(0).calCost(userRecords.getCallingInCityRecords())
				+ super.getChargeRules().get(1).calCost(userRecords.getCallingInProvinceRecords())
				+ super.getChargeRules().get(2).calCost(userRecords.getCallingInLandRecords());
		return sum;
	}

	@Override
	public double getMonthlyRent() {
		// TODO 自动生成的方法存根
		return this.montlyRent;
	}

}
class LandPhoneInCityRule extends CallChargeRule {

	public double calCost(ArrayList<CallRecord> callRecords) {
		double sum = 0;
		for (CallRecord a : callRecords)
			sum = sum + Math.ceil((a.getEndTime().getTime() - a.getStartTime().getTime()) / 1000.0 / 60.0);
		sum = sum * 0.1;
		return sum;
	}

}
 class LandPhoneInLandRule extends CallChargeRule {

	@Override
	public double calCost(ArrayList<CallRecord> callRecords) {
		// TODO 自动生成的方法存根
		double sum = 0;
		for (CallRecord a : callRecords)
			sum = sum + Math.ceil((a.getEndTime().getTime() - a.getStartTime().getTime()) / 1000.0 / 60.0);
		sum = sum * 0.6;
		return sum;
	}

}
class LandPhoneInProvinceRule extends CallChargeRule {
	public double calCost(ArrayList<CallRecord> callRecords) {
		double sum = 0;
		for (CallRecord a : callRecords)
			sum = sum + Math.ceil((a.getEndTime().getTime() - a.getStartTime().getTime()) / 1000.0 / 60.0);
		sum = sum * 0.3;
		return sum;
	}

}

 

分析:

  • 这一次的题目集在上一次题目集的基础上增加了手机打电话计费方式,根据手机套餐的不同进行不同的费用计算,并且要根据手机现所在地判断是省内漫游或是省外漫游,不同漫游方式每小时价格不同,以及接听电话也要计费,在不同地区接听电话计费价格也不同。
  • 我在上一次的源码上进行添加,新建了关于手机的通话记录以及计费方式的类。

 

踩坑心得:

  • 在这一次题目集我学习了上一次题目集的经验,一拿到题目,就将上一次的正则表达式删去,全部重新写了一遍,防止因为正则表达式导致的错误,从结果来看效果很好,避免了因为判断格式错误所导致的结果错误,从而避免浪费时间。
  • 在这次的题目集上,我依旧用了上次的判断加通话记录的条件,导致错误,这题在主函数内通过判断接听电话所在区号找到对应的计费规则类,在此类里继续通过所拨打电话所在地区区号判断应该如何计费,这说明我上题代码写的不够完善,没有扩展性,设计不合理。
  • 在完成对通话记录条件的这一部分后,发现在类里,我不能找到用户的区号,于是发现,我在构造方法时没有将区号传进用户数据里,所以导致报错,于是我重新写了用户的构造方法,解决了此问题。

 

题目3).

电信计费系列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.

注意:以上两类信息,先输入所有开户信息,再输入所有通讯信息,最后一行以“end”结束。
输出:
根据输入的详细短信信息,计算所有已开户的用户的当月短信费用(精确到小数点后2位,单位元)。假设每个用户初始余额是100元。
每条短信信息均单独计费后累加,不是将所有信息累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略。
本题只做格式的错误判断,无需做内容上不合理的判断,比如同一个电话两条通讯记录的时间有重合、开户号码非南昌市的号码、自己给自己打电话等,此类情况都当成正确的输入计算。但时间的输入必须符合要求,比如不能输入2022.13.61 28:72:65。

本题只考虑短信计费,不考虑通信费用以及月租费。

 

设计类图如下:

 

SourceMonitor报表如下:

 

代码如下:

code
import java.util.Scanner;
import java.util.TreeMap;
import java.util.ArrayList;
public class Main {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Scanner input = new Scanner(System.in);
		TreeMap<String, User> records = new TreeMap<String, User>();
		String checkUphone = "u-1\\d{10}\\s3";
		String checkM = "m-1\\d{10}\\s1\\d{10}\\s[A-Za-z0-9,. ]{1,}";
		String a = input.nextLine();
		while (!a.equals("end")) {
			if (a.matches(checkUphone)) {
				String[] array = a.substring(2).split(" ");
				String number = array[0];
				MessageCharging mode = new MessageCharging();// 你开户想要的套餐
				User user = new User(number, mode);// 开户 并且将你开户的号码与套餐传进用户里
				records.put(number, user);// 将这个用户信息传到这个容器里
			}
			if(a.matches(checkM)) {
				String[] array = a.substring(2).split(" ");
				String message = a.substring(26);
				String callingNumber = array[0];// 拨打电话号码
				String answerNumber = array[1];// 接听电话号码
				MessageRecord messagerecord = new MessageRecord(message);
				if (records.get(callingNumber) != null)
					records.get(callingNumber).getUserRecords().addSendMessageRecords(messagerecord);
			}
			a = input.nextLine();
		}
		for(User user : records.values()) {
		System.out.println(user.getNumber()+" "+String.format("%.1f",user.calCost())+" "+user.calBalance());
		}
	}

}
abstract class MessageChargeRule extends ChargeRule {

	public abstract double calCost(ArrayList<MessageRecord> messageRecord);

}
class MessageCharging extends ChargeMode {

	@Override
	public double calCost(UserRecords userRecords) {
		// TODO 自动生成的方法存根
		double sum = 0;
		getChargeRules().add(new SendMessageRule());
		sum = ((SendMessageRule)super.getChargeRules().get(0)).calCost(userRecords.getSendMessageRecords());
		return sum;
	}

	@Override
	public double getMonthlyRent() {
		// TODO 自动生成的方法存根
		return 0;
	}

}
class MessageRecord{
	String message;
	String sendNumber;
	String receiveNumber;

	public MessageRecord(String message) {
		super();
		// TODO 自动生成的构造函数存根
		
		this.message = message;
	}

	public String getSendNumber() {
		return sendNumber;
	}

	public void setSendNumber(String sendNumber) {
		this.sendNumber = sendNumber;
	}

	public String getReceiveNumber() {
		return receiveNumber;
	}

	public void setReceiveNumber(String receiveNumber) {
		this.receiveNumber = receiveNumber;
	}

	public String getMessage() {
		return message;
	}

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

}
class SendMessageRule extends MessageChargeRule {

	@Override
	public double calCost(ArrayList<MessageRecord> messageRecords) {
		// TODO 自动生成的方法存根
		double sum = 0, b, n = 0;
		for (MessageRecord a :  messageRecords) {
			b = Math.ceil(((MessageRecord)a).getMessage().length() / 10.0);
			n = n + b;
		}
		if (n <= 3) {
			sum = n * 0.1;
		}
		if (n > 3 && n <= 5) {
			sum = 0.3 + (n - 3) * 0.2;
		}
		if (n > 5) {
			sum = 0.7 + (n - 5) * 0.3;
		}

		return sum;
	}

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

	public User(String number, ChargeMode mode) {
		// TODO 自动生成的构造函数存根
		this.number = number;
		this.chargeMode = mode;
	}

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

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

	public UserRecords getUserRecords() {
		return userRecords;
	}

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

	public double getBalance() {
		return balance;
	}

	public void setBalance(double balance) {
		this.balance = balance;
	}

	public ChargeMode getChargeMode() {
		return chargeMode;
	}

	public void setChargeMode(ChargeMode chargeMode) {
		this.chargeMode = chargeMode;
	}

	public String getNumber() {
		return number;
	}

	public void setNumber(String number) {
		this.number = number;
	}

}
class UserRecords {

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

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

	public void setSendMessageRecords(ArrayList<MessageRecord> sendMessageRecords) {
		this.sendMessageRecords = sendMessageRecords;
	}

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

	public void setReceiveMessageRecords(ArrayList<MessageRecord> receiveMessageRecords) {
		this.receiveMessageRecords = receiveMessageRecords;
	}

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

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

}


abstract class ChargeMode {
	ArrayList<ChargeRule> chargeRules = new ArrayList<ChargeRule>();

	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();

}
abstract class ChargeRule {

}

 

分析:

  • 这一次题目集与前两道题相比难度较小,只有一个短信计费,于是我在之前代码的基础上删去了许多无用的代码,并且添加了电信计费的相关类,并在类内实现了各个类的功能。
  • 这次的题目集只需要阅读清楚题目要求,其按照短信长度计算短信条数,并且根据短信条数不同存在不同的计费方式。

 

踩坑心得:

  • 这次的题目集较为简单,所以踩坑较少,在修改之前代码时,发现十分麻烦,因为有许多无用代码,导致找到自己所需要的东西需要花费很多时间,所以我新建了一个项目,将所需要的类保留下来,这样节省了时间,在简化后的项目了增加这题所需要实现的功能。
  • 在开始,没有看清楚题目,误以为超过三条短信后每条短信价格都发生了改变,导致了计算错误,在之后我自己计算了一遍所给输入数据,对照输出结果,发现是超过的部分按照改变后的价格计算费用,在修改完后这道题就通过了,说明题目再简单也要看清楚题目。

 

改进建议:

  • 这三次的题目集关于电信业务资费的,其中涉及到了继承、多态、抽象类、集合框架等知识点,第一次题目集只有两道题,题目量较少,第一题关于移动业务资费难度较大,因为题目给出的类图是分开的,我们需要先根据给出的类图理解,并且掌握类与类之间的所有关系,其中还包括许多的抽象类,在抽象类中写出子类所共有的抽象方法,第一次代码需要有扩展性以及可延续性,所以要考虑的更为谨慎,因此第一次写代码所花费时间更长。
  • 在第一次题目集的基础上,第二次题目集无疑是提高了难度,如果第一次题目集设计不合理,写第二次题目集意味着要重新写过代码,这是十分不可取的。第二次题目集的计费规则相比第一次复杂了很多,由于增加了手机套餐,以及手机区号,手机所在地区号,这些数据的不同均会导致计费方式的不同,在书写判断条件时,要更加小心,我最开始想要在主函数内将所有情况写出来一一对应添加到相应的计费规则记录里,但是发现这样考虑的并不够全面,最后改进通过主函数判断接听电话所在地区区号,再在对应的计费规则类中通过打电话所在地区区号将通话记录添加到对应的记录里,由于有第一次题目集的基础,所以虽然第二次题目集更为复杂,但是所花时间并没有第一次题目集长。
  • 第三次题目集相对于前两次较为简单,只需要考虑短信计费问题,通过判断字符串长度计算出短信条数,再根据短信条数计算出所需要费用,这道题主要出错问题是理解错了题目意思,所以在以后的题目中需要更加仔细阅读题目,避免此类原因造成错误的发生。
  • 总的来说这几次题目集难度还是有的,在遇到难题时不能存在不敢下手的这种情况,要就算知道自己可能写不出来,还要硬着头皮继续去写,去付出时间,这样自己的编程水平才会有所提高。

 

总结:

  • 这学期由于疫情,在寝室上了很久的网课,对于Java这门课来说,我觉得影响挺大的,对于我来说,上网课的效率是真的太差了,导致自己需要花费很多课后的时间去自学很多东西。
  • 并且要在完成pta的情况下,我认为这学期的题目集难度提升了很多,所花费的时间更多了,这更让我意识到自己编程能力远远不够。
  • 这几次的作业让我感受到了编写代码需要严谨,要考虑每种不同的情况,这样才能保证程序没有漏洞,在不严谨的思绪下写出来的代码,可能你用数据测试最后得到的结果却是正确的,最后找不到漏洞在哪,需要花更大量的时间去找到漏洞并且修复。
  • 希望自己在每次再编写代码时足够专心,不能被其他东西吸引注意力。

posted on 2022-06-16 21:13  21206104-戴奕为  阅读(30)  评论(0编辑  收藏  举报

导航