南昌航空大学大一下学期java-题目集1~3总结性Blog——苏礼顺23201608

Zurichsls / 2024-04-20 / 原文

一、前言

——总结三次题目集的知识点、题量、难度等情况 

  《面向对象程序设计》这一门课,是教授我们设计代码,掌握类、类间关系,以及面向对象的三大设计原则——封装、继承、多态等面向对象的基本概念和方法,并以面向对象的编程语言java语言设计程序。因此在这三次的题目集都与类的设计与使用有关。

  这三次题目集目前仅涉及“封装继承多态”三大特性中的“封装”,尽管如此,题目集中的题目还是有一定的难度。并且三次题目集对于类的知识点涵盖极广,包括但不限于类的声明,创建,使用方法,类的构造方法,成员变量,成员方法的定义与使用方法。还有java语言中包的概念,以及papckage,import语句的使用,类中的组合、聚合、依赖、关联关系,java中方法的重载的实现方式等。

  题目集一有五题,题目集二四题,题目集三三题。题目难度逐渐递增。值得一提的是:每次题目集的最后一题都是“答题判断程序”有关的题目。输入的内容包括:题目内容,试卷内容,删除题目等等,最后要求实现模拟小型测试,按要求输出判断结果。三次题目逐渐迭代,设计的类逐渐增多,可实现的功能也逐渐增多。目前没有增加继承与多态,但是后续的此题迭代则会依次增加。题目具有一定挑战度,同时也是对我们类的掌握程度的考验!!

二、设计与分析

——主要是对题目以及自己提交的源码进行分析,加上自己浅浅的解释和心得

(一)题目集一

题目一二都是对类的简单使用,除了主类之外,其他的类只有一个,且都是实体类只要按照题目要求,定义适当的类的属性与方法就可以解决问题。特别地,在使用toString方法的时候,它的返回类型只能是String类型。

题目三四则是关于计算成绩统计类的题目。第三题通过循环依次读入信息,再进行处理与输出。第四题设计了Score类与Student类。Score类放了平时成绩与期末成绩,Student类与Score类是关联关系,一个学生对应他自己的语文、数学、物理成绩。这题自己的出彩之处在于Main里面的对数据的读入的处理方法,两层循环,减少了写读入语句的次数。见如下代码:

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        for(int  i = 0; i < 3; i++) {       
        	String id = in.next();
            String name = in.next();
            Score chinese = new Score();
            Score math = new Score();
            Score physics = new Score();
            for(int j = 0; j < 3;j++) {
            	if(j!=0) {
            		String id0 = in.next();
                    String name0 = in.next();
            	}
                String subject = in.next();
                int score1 =in.nextInt();
                int score2 = in.nextInt();
                if(subject.equals("语文")) {
                	chinese.setUsual(score1);
                	chinese.setTerm(score2);
                }
                if(subject.equals("数学")) {
                	math.setUsual(score1);
                	math.setTerm(score2);
                }
                if(subject.equals("物理")) {
                	physics.setUsual(score1);
                	physics.setTerm(score2);
                }
            }
        	Student stu = new Student(name, id, chinese,math,physics);
            stu.printlnfo();
            System.out.printf("\n");
        }
    }
}

题目五是“答题判题程序-1”

输入格式:

程序输入信息分三部分:

1、题目数量

   格式:整数数值,若超过1位最高位不能为0,

   样例:34

2、题目内容

   一行为一道题,可以输入多行数据。

   格式:"#N:"+题号+" "+"#Q:"+题目内容+" "#A:"+标准答案

格式约束:题目的输入顺序与题号不相关,不一定按题号顺序从小到大输入。

   样例:#N:1 #Q:1+1= #A:2

         #N:2 #Q:2+2= #A:4

3、答题信息

   答题信息按行输入,每一行为一组答案,每组答案包含第2部分所有题目的解题答案,答案的顺序号与题目题号相对应。

   格式:"#A:"+答案内容

   格式约束:答案数量与第2部分题目的数量相同,答案之间以英文空格分隔。

   样例:#A:2 #A:78

      2是题号为1的题目的答案
      78是题号为2的题目的答案

   答题信息以一行"end"标记结束,"end"之后的信息忽略。

输出格式:

1、题目数量

   格式:整数数值,若超过1位最高位不能为0,

   样例:34

2、答题信息

   一行为一道题的答题信息,根据题目的数量输出多行数据。

   格式:题目内容+" ~"+答案

   样例:1+1=~2

          2+2= ~4

3、判题信息

   判题信息为一行数据,一条答题记录每个答案的判断结果,答案的先后顺序与题目题号相对应。

   格式:判题结果+" "+判题结果

   格式约束:

     1、判题结果输出只能是true或者false,
     2、判题信息的顺序与输入答题信息中的顺序相同

   样例:true false true

输入样例1:

单个题目。例如:

1
#N:1 #Q:1+1= #A:2
#A:2
end

输出样例1:

在这里给出相应的输出。例如:

1+1=~2
true

输入样例2:

单个题目。例如:

1
#N:1 #Q:1+1= #A:2
#A:4
end

输出样例2:

在这里给出相应的输出。例如:

1+1=~4
false

输入样例3:

多个题目。例如:

2
#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#A:2 #A:4
end

输出样例3:

在这里给出相应的输出。例如:

1+1=~2
2+2=~4
true true

输入样例4:

多个题目。例如:

2
#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#A:2 #A:2
end

输出样例4:

在这里给出相应的输出。例如:

1+1=~2
2+2=~2
true false

输入样例5:

多个题目,题号顺序与输入顺序不同。例如:

2
#N:2 #Q:1+1= #A:2
#N:1 #Q:5+5= #A:10
#A:10 #A:2
end

输出样例5:

在这里给出相应的输出。例如:

5+5=~10
1+1=~2
true true

输入样例6:

含多余的空格符。例如:

1
#N:1 #Q: The starting point of the Long March is #A:ruijin
#A:ruijin
end

输出样例6:

在这里给出相应的输出。例如:

The starting point of the Long March is~ruijin
true

输入样例7:

含多余的空格符。例如:

1
#N: 1 #Q: 5 +5= #A:10
#A:10
end

输出样例7:

在这里给出相应的输出。例如:

5 +5=~10
true

让我们分析下题目:

  题目输入分为三个部分

  1.输入题目数量,因此已知题目数量,便可以考虑利用确定长度的数组进行对题目的存储。

  2.题目输入的形式为“#N:1 #Q:1+1= #A:2”,其中我们只要“1 1+1= 2”这题号,题目内容,标准答案这三个部分,因此考虑正则表达式进行分割。

  3.接着是输入答题信息,每一行便会输入所有题目的答题信息,因此我们有两种读取方式:

  • 一是:我们整行读取信息后,便需要提取对我们有用的信息,即他输入“#A:2”,但是我们只需要他的“2”,先进行空字符进行分割,然后再对每一个分割的部分进行去除“#A:”的操作得到我们想要的最终答案。
  • 二是:因为我们前面已经知道了题目总数,而且题目也告知我们“答案数量与第二部分题目数量相同”,因此我们进行循环读入,读入次数就为题目的总数量,这样我们就一次的得到了“#A:2”的内容,然后我们进行去除“#A:”的操作就可以了。

  经过上述的分析,我们也大致可以确定了我们可以用三个实体类来进行我们的信息读入。

  • Question类存储no-题目序号,questionTest-题目文本,standAnwer-题目标准答案。
  • Paper类用来存储Question类型的数组,即组装试卷。
  • Answer类有Paper类型的对象,也有String类型的数组,来是对我们的自己的答案进行存储,还有一个boolean类型的名为judgeAnswer的数组,进行我们的判断答案进行存储。

  题目输出形式也为三个部分

  1.输出题目数量

  2.输出答题信息,输出形式为“题目内容+" ~"+答案”。另外我们观察一种题目的输入输出样例:

输入:2             输出:5+5=~10
     #N:2 #Q:1+1= #A:2        1+1=~2
     #N:1 #Q:5+5= #A:10                     true true
     #A:10 #A:2
     end

在这一个输入与输出样例中,输入的题目顺序是21但是题目数出的顺序是1,2,再联想到上面的输入答题信息时,“题目的输入顺序与题号不相关,不一定按题号顺序从小到大输入。”以及:输入自己的答题信息时:“答案的顺序号与题目题号相对应”,因此自己对题目信息进行存储后,需要进行题目序号的排序,才能进行相应的后面的判断处理。

  3.输出题目数量,输出答题信息,输出形式为“题目内容+" ~"+答案”,然后输出判题信息即trur 或者 false。

  下面是自己代码:

题目集一最后一题
 package one_seven_oop1_last;

import java.util.Scanner;

public class Last1 {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        String wu = in.nextLine();
        Question[] questions = new Question[n]; 
        // 传入题目序号,题目,标准答案
        for(int i = 0; i < n ; i++) {
        	String list = in.nextLine();
        	String[] text = list.split("\\s*#N:\\s*|\\s*#Q:\\s*|\\s*#A:\\s*");
        	int k = Integer.parseInt(text[1]);
        	Question question = new Question(k,text[2],text[3]);
        	questions[i] = question;
        }
        
        Paper paper = new Paper(questions,n);
        
        // 传入答题的答案
        String[] answer = new String [n];
        for(int i =0; i < n + 1; i++) {
        	String answerList = in.next();
        	if(answerList.equals("end"))
        		break;
        	String[] text = answerList.split("\\s*A:\\s*");
        	answer[i] = text[1];
        }
        Answer answers = new Answer(paper);
        answers.setAnswes(answer);
        answers.println(); 
    }
}

class Question {
	private int no;
	private String questionText;
	private String standardAnswer; 
	
	Question(){
	}

	public Question(int no, String questionText, String standardAnswer) {
		super();
		this.no = no;
		this.questionText = questionText;
		this.standardAnswer = standardAnswer;
	}

	public int getNo() {
		return no;
	}

	public void setNo(int no) {
		this.no = no;
	}

	public String getQuestionText() {
		return questionText;
	}

	public void setQuestionText(String questionText) {
		this.questionText = questionText;
	}

	public String getStandardAnswer() {
		return standardAnswer;
	}

	public void setStandardAnswer(String standardAnswer) {
		this.standardAnswer = standardAnswer;
	}

	public boolean answerJudge(String answer) {
		if(standardAnswer.equals(answer))
			return true;
		else
			return false;
	}
}

class Paper {
	private Question[] question;
	private int num;
	
	public Paper() {
		super();
	}

	public Paper(Question[] question, int num) {
		this.question = question;
		this.num = num;
	}

	public Question getQuestion(int i) {
		return question[i];
	}

	public void setQuestion(Question[] question) {
		this.question = question;
	}

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}
	
	// 对题目排序
	public void sortQuestions() {
		for(int i = 0; i< num-1; i++) {
			for(int j = 0; j <num - 1 - i; j++) {
				Question t= new Question();
				if(question[j].getNo() > question[j+1].getNo()) {
					t = question[j];
					question[j] = question[j+1];
					question[j+1] = t;
				}
			}
		}
	}
}

class Answer {
	private Paper paper = new Paper();
	private String[] Answers;
	private boolean[] judgeAnswer = new boolean[paper.getNum()];;
	
	Answer(Paper paper){
		this.paper = paper;
		this.judgeAnswer = new boolean[paper.getNum()];
	}

	public Paper getPaper() {
		return paper;
	}

	public void setPaper(Paper paper) {
		this.paper = paper;
	}

	public String getAnswes(int i) {
		return Answers[i];
	}

	public void setAnswes(String[] standardAnswes) {
		this.Answers = standardAnswes;
	}

	public boolean[] getJudgeAnswer() {
		return judgeAnswer;
	}

	public void setJudgeAnswer(boolean[] judgeAnswer) {
		this.judgeAnswer = judgeAnswer;
	}
	
	public boolean[] compare() {
		for(int i = 0; i < paper.getNum(); i++) {
			if(paper.getQuestion(i).answerJudge(Answers[i]))
				judgeAnswer[i] = true;
			else
				judgeAnswer[i] = false;
		}
		return judgeAnswer;
	}
	
	public void println() {
		paper.sortQuestions();
		for(int i = 0; i < paper.getNum() ; i++) {
			System.out.printf(paper.getQuestion(i).getQuestionText() + "~" + getAnswes(i) + "\n");
		}
		compare();
		for(int i = 0; i < paper.getNum(); i++) {
			System.out.printf(judgeAnswer[i]+"");
			if(i != paper.getNum()-1)
				System.out.printf(" ");
		}
		
	}

}

  代码如上述所述,根据SOURCEMONITIOR生成的情况来看:

根据数据与雷达图分析:

  • 分支语句占比总语句数的百分比为12.8%,此比例较低,说明此代码中分支逻辑较少,更易于理解与维护
  • 在雷达图中注释语句占总语句数的百分比最低,说明我的代码可读性较差,可能也难以理解和维护,因此要增加代码的注释比例
  • 同时,每个方法的平均语句和数量也较低,可能是因为这段代码不是很复杂,较多的set与get语句使得方法的平均语句和数量较低

而结合自己的代码编写的实际来看,三个类的类间关系设计的并不合理,Question与Paper之间是聚合关系,因为试卷包含题目,而Answer与paper是关联关系,这两个之间的耦合性太强了。我们学过MVC模式,应该放置一个控制类controller,进行对信息的处理,同时写一个view类,来进行对信息的输出。此外,对于题目序号的排序可以进行compareTo方法的重写。而不是用冒泡排序。


(二)题目集二

题目一是是对手机的价格排序以及查找。

这一题新学到了两个东西,一个是ArrayList实现动态数组大小没有限制,一个是利用实现comparable接口,重写compareTo方法,,实行对price的大小来确定手机对象的大小关系 。通过Collections类的sort方法对链表中的对象按照price升序排序。

题目二三则是对类的成员变量,构造方法,等的简单使用。

题目四是“答题判题程序-2”

设计实现答题程序,模拟一个小型的测试,以下粗体字显示的是在答题判题程序-1基础上增补或者修改的内容

要求输入题目信息、试卷信息和答题信息,根据输入题目信息中的标准答案判断答题的结果。

输入格式:

程序输入信息分三种,三种信息可能会打乱顺序混合输入

1、题目信息

   一行为一道题,可输入多行数据(多道题)。

   格式:"#N:"+题目编号+" "+"#Q:"+题目内容+" "#A:"+标准答案

格式约束:

    1、题目的输入顺序与题号不相关,不一定按题号顺序从小到大输入。
    2、允许题目编号有缺失,例如:所有输入的题号为1、2、5,缺少其中的3号题。此种情况视为正常。

   样例:#N:1 #Q:1+1= #A:2

         #N:2 #Q:2+2= #A:4

2、试卷信息

一行为一张试卷,可输入多行数据(多张卷)。

格式:"#T:"+试卷号+" "+题目编号+"-"+题目分值

     题目编号应与题目信息中的编号对应。

     一行信息中可有多项题目编号与分值。

样例:#T:1 3-5 4-8 5-2

3、答卷信息

    答卷信息按行输入,每一行为一张答卷的答案,每组答案包含某个试卷信息中的题目的解题答案,答案的顺序与试卷信息中的题目顺序相对应。

   格式:"#S:"+试卷号+" "+"#A:"+答案内容

   格式约束:答案数量可以不等于试卷信息中题目的数量,没有答案的题目计0分,多余的答案直接忽略,答案之间以英文空格分隔。

   样例:#S:1 #A:5 #A:22

       1是试卷号 

       5是1号试卷的顺序第1题的题目答案

       22是1号试卷的顺序第2题的题目答案

   答题信息以一行"end"标记结束,"end"之后的信息忽略。

输出格式:

1、试卷总分警示

该部分仅当一张试卷的总分分值不等于100分时作提示之用,试卷依然属于正常试卷,可用于后面的答题。如果总分等于100分,该部分忽略,不输出。

   格式:"alert: full score of test paper"+试卷号+" is not 100 points"

   样例:alert: full score of test paper2 is not 100 points

2、答卷信息

   一行为一道题的答题信息,根据试卷的题目的数量输出多行数据。

   格式:题目内容+"~"+答案++"~"+判题结果(true/false)

约束:如果输入的答案信息少于试卷的题目数量,答案的题目要输"answer is null"   

样例:3+2=~5~true

         4+6=~22~false.

      answer is null

3、判分信息

   判分信息为一行数据,是一条答题记录所对应试卷的每道小题的计分以及总分,计分输出的先后顺序与题目题号相对应。

   格式:题目得分+" "+....+题目得分+"~"+总分

   格式约束:

 1、没有输入答案的题目计0分

 2、判题信息的顺序与输入答题信息中的顺序相同

   样例:5 8 0~13

根据输入的答卷的数量以上2、3项答卷信息与判分信息将重复输出。

4、提示错误的试卷号

如果答案信息中试卷的编号找不到,则输出”the test paper number does not exist”,参见样例9。

 

设计建议:

参考答题判题程序-1,建议增加答题类,类的内容以及类之间的关联自行设计。

输入样例1:

一张试卷一张答卷。试卷满分不等于100。例如:

#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-5 2-8
#S:1 #A:5 #A:22
end

输出样例1:

在这里给出相应的输出。例如:

alert: full score of test paper1 is not 100 points
1+1=~5~false
2+2=~22~false
0 0~0

输入样例2:

一张试卷一张答卷。试卷满分不等于100。例如:

#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-70 2-30
#S:1 #A:5 #A:22
end

输出样例2:

在这里给出相应的输出。例如:

1+1=~5~false
2+2=~22~false
0 0~0

输入样例3:

一张试卷、一张答卷。各类信息混合输入。例如:

#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-70 2-30
#N:3 #Q:3+2= #A:5
#S:1 #A:5 #A:4
end

输出样例:

在这里给出相应的输出。例如:

1+1=~5~false
2+2=~4~true
0 30~30

输入样例4:

试卷题目的顺序与题号不一致。例如:

#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 2-70 1-30
#N:3 #Q:3+2= #A:5
#S:1 #A:5 #A:22
end

输出样例:

在这里给出相应的输出。例如:

2+2=~5~false
1+1=~22~false
0 0~0

输入样例5:

乱序输入。例如:

#N:3 #Q:3+2= #A:5
#N:2 #Q:2+2= #A:4
#T:1 3-70 2-30
#S:1 #A:5 #A:22
#N:1 #Q:1+1= #A:2
end

输出样例:

在这里给出相应的输出。例如:

3+2=~5~true
2+2=~22~false
70 0~70

输入样例6:

乱序输入+两份答卷。例如:

#N:3 #Q:3+2= #A:5
#N:2 #Q:2+2= #A:4
#T:1 3-70 2-30
#S:1 #A:5 #A:22
#N:1 #Q:1+1= #A:2
#S:1 #A:5 #A:4
end

输出样例:

在这里给出相应的输出。例如:

3+2=~5~true
2+2=~22~false
70 0~70
3+2=~5~true
2+2=~4~true
70 30~100

输入样例7:

乱序输入+分值不足100+两份答卷。例如:

#N:3 #Q:3+2= #A:5
#N:2 #Q:2+2= #A:4
#T:1 3-7 2-6
#S:1 #A:5 #A:22
#N:1 #Q:1+1= #A:2
#S:1 #A:5 #A:4
end

输出样例:

在这里给出相应的输出。例如:

alert: full score of test paper1 is not 100 points
3+2=~5~true
2+2=~22~false
7 0~7
3+2=~5~true
2+2=~4~true
7 6~13

输入样例8:

乱序输入+分值不足100+两份答卷+答卷缺失部分答案。例如:

#N:3 #Q:3+2= #A:5
#N:2 #Q:2+2= #A:4
#T:1 3-7 2-6
#S:1 #A:5 #A:22
#N:1 #Q:1+1= #A:2
#T:2 2-5 1-3 3-2
#S:2 #A:5 #A:4
end

输出样例:

在这里给出相应的输出。例如:

alert: full score of test paper1 is not 100 points
alert: full score of test paper2 is not 100 points
3+2=~5~true
2+2=~22~false
7 0~7
2+2=~5~false
1+1=~4~false
answer is null
0 0 0~0

输入样例9:

乱序输入+分值不足100+两份答卷+无效的试卷号。例如:

#N:3 #Q:3+2= #A:5
#N:2 #Q:2+2= #A:4
#T:1 3-7 2-6
#S:3 #A:5 #A:4
end

输出样例:

在这里给出相应的输出。例如:

alert: full score of test paper1 is not 100 points
The test paper number does not exist

让我们分析下题目:

  对于输入信息

  1.首先是此次题目相对于上次题目最大的不同-就是增加了试卷信息,对于试卷信息里面包含了试卷号,题目编号与题目分值然后是输入信息:

  2.题目信息-这次没有输入题目数量,只是题目信息,因此不能用定长度的数组来进行对题目信息的存储,而是利用题目一学的Arraylist存储题目的数据。
  3.试卷信息-一行为一张试卷,可输入多行试卷,
  4.答卷信息-这次的答案信息也多试卷的卷号这一条信息,然后自己的答案按照对应试卷的题目顺序来进行输入
  5.设计考虑:试卷类在上一次题目中已经被定义了,因此在上次设计上增加答卷类,用于封装答卷信息。
  对于输出信息:
  1.输出试卷总分警示:仅当一张试卷的总分分值不等于100分时作提示之用。
  2.答卷信息-与上一次的输入一样,不同的是有输出“answer is null”这一种信息。因此最初的设计思路是考虑先遍历试卷,因为题目的试卷的题目数量是一定的,然后找出对应的答题卷,当没有这一题的时候将输出 “answer is null”。同时当对应的答题卷子 找不到的时候,则会输出“the test paper number does not exist”。
  3.接着输出判分信息判断每一题的得分。并且汇总总分数。

  下面是自己代码:

题目集二最后一题
 package one_seven_oop2_last;

import java.util.Collections;
import java.util.ArrayList;
import java.util.Scanner;

public class Last2 {
	public static void main(String[] args) {
		Scanner  in = new Scanner(System.in);
		ArrayList<Question> question = new ArrayList<Question>();
		ArrayList<TestPaper> textPaper = new ArrayList<TestPaper>();
		ArrayList<Answer> answer = new ArrayList<Answer>();

		String input = in.nextLine();
		
//		int cnt = 0;
		while(!input.equals("end")) {
			// 对一行问题进行读取与解析
			if(input.contains("#N")) {
				// controller
        		String[] text = input.split("\\s*#N:\\s*|\\s*#Q:\\s*|\\s*#A:\\s*");// 分割
            	Integer.parseInt(text[1]);// 读取题号
            	Question q = new Question(Integer.parseInt(text[1]),text[2],text[3]);
            	question.add(q);// 加入question的数组
			}
			
			else if(input.contains("#T")) {
        	    String[] texts = input.split("\\s*#T:\\s*|\\s+");// 第一次拆分
        	    TestPaper p = new TestPaper( (Integer.parseInt(texts[1])) );
        	    textPaper.add(p);
        		ArrayList<Question> q = new ArrayList<Question>();
        		
        	    for(int i = 2; i < texts.length; i++) {
        	        String text = texts[i];
        	        String[] singleText = text.split("-");// 第二次拆分
        	        // 传入每一题的分数
        	        for(int j = 0; j < question.size(); j++) {
        	            if(question.get(j).getNumber() == Integer.parseInt(singleText[0])) {
        	            	Question q1 = new Question(question.get(j).getNumber(),question.get(j).getContent(), question.get(j).getStandAnswer(), Integer.parseInt(singleText[1]));
        	                q.add(q1);
//        	            	question.get(j).setScore(Integer.parseInt(singleText[1]));
//        	                q.add(question.get(j));
        	            }
        	        }
        	    }
        	    p.setQuestion(q);
        	    //cnt = question.size();// 这个操作是为了让每次卷子生成的时候,从上一步结束后的问题列表继续开始
			}
			
			else if(input.contains("#S")) {
				// 读入自己的答案
        		String[] texts = input.split("\\s*#S:\\s*|\\s+");
        		Answer a = new Answer(Integer.parseInt(texts[1]));
        		ArrayList<String> list = new ArrayList<String>();
        		for (int i = 2; i < texts.length; i++) {
        		    String text = texts[i];
        		    String[] singleText = text.split("\\s*#A:\\s*");
        		    list.add(singleText[1]);
        		}
        		String[] array =list.toArray(new String[list.size()]);
        		a.setSelfAnswer(array);
        		answer.add(a);
			}
			
			else if(input.equals("end"))
        		break;
				
			input = in.nextLine();


		}
		
		AnswerSheet answerSheet = new AnswerSheet();
		answerSheet.setAnswer(answer);
		
//		 判断每张试卷的总分数
		for(int i = 0;  i < textPaper.size(); i++) {
        	int t = 0;
        	for(int j = 0; j < textPaper.get(i).getQuestion().size(); j++) {
        		t = t + textPaper.get(i).getQuestion().get(j).getScore();
        	}
        	if(t != 100)
        		System.out.println("alert: full score of test paper"+(i+1)+" is not 100 points");
        }
		
//		answerSheet.getAnswer().size()
//		textPaper.size()
		int choice1 = 0, choice2 = 0;
		for(int i =0; i < answerSheet.getAnswer().size(); i++) {
			choice2 = 0;
			for(int j = 0; j < textPaper.size(); j++) {
				choice1 = 0;
				if(textPaper.get(j).getNumber() == answerSheet.getAnswer().get(i).getNumber()) {
					choice1 = 1;
					choice2 = 1;
					TestPaper p = textPaper.get(j);
					String[] selfanswer = answerSheet.getAnswer().get(i).getSelfAnswer();
					int[] score =  new int[p.getQuestion().size()];
					for(int k =0; k < p.getQuestion().size(); k++) {
						score[k] = p.getQuestion().get(k).getScore();
					}
					for(int k = 0; k < selfanswer.length; k++) {
						String d1 = p.getQuestion().get(k).getStandAnswer();
						String d2 = selfanswer[k];
						String result = d1.equals(d2) ? "true" : "false";
						if(result.equals("false"))
							score[k] = 0;
						System.out.println(p.getQuestion().get(k).getContent()+"~"+d2+"~"+result);
					}
					if(selfanswer.length < p.getQuestion().size()) {
						for(int k = selfanswer.length;k < p.getQuestion().size();k++)
							System.out.println("answer is null");
						if(selfanswer.length == 0)
							break;
						for(int w =selfanswer.length; w < p.getQuestion().size();w++)
							score[w] = 0;
					}

					int total = 0;
					for(int k = 0; k < score.length; k++) {
                    	total = total + score[k];
                    	System.out.printf("%d",score[k]);
                    	if(k!=score.length-1)
                    		System.out.printf(" ");
                    }
					System.out.println("~"+total);
				}
				
			}
			if(choice1== 0 && choice2 == 0)
				System.out.println("The test paper number does not exist");
		}

		
	}
}

// 问题类——封装一个试卷的所有属性与方法 
class Question {
	private int number;// 题号
	private String content;// 题目
	private String standAnswer;// 题目标准答案
	private int score;// 题目分数
	
	public Question() {
		super();
	}

	public Question(int number, String content, String standAnswer) {
		super();
		this.number = number;
		this.content = content;
		this.standAnswer = standAnswer;
	}

	public Question(int number, String content, String standAnswer, int score) {
		super();
		this.number = number;
		this.content = content;
		this.standAnswer = standAnswer;
		this.score = score;
	}

	public int getNumber() {
		return number;
	}

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

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public String getStandAnswer() {
		return standAnswer;
	}

	public void setStandAnswer(String standAnswer) {
		this.standAnswer = standAnswer;
	}

	public int getScore() {
		return score;
	}

	public void setScore(int score) {
		this.score = score;
	}
	
	
}

// 试卷类——封装一种卷子
class TestPaper {
	private ArrayList<Question> question = new ArrayList<Question>();// 一种试卷有多张卷子
	private int number;// 此种试卷对应的编号
	
	public TestPaper() {
		super();
	}

	public TestPaper(int number) {
		super();
		this.number = number;
	}

	public TestPaper(ArrayList<Question> question, int number) {
		super();
		this.question = question;
		this.number = number;
	}

	public ArrayList<Question> getQuestion() {
		return question;
	}

	public void setQuestion(ArrayList<Question> question) {
		this.question = question;
	}

	public int getNumber() {
		return number;
	}

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

// 答案类——封装一张答卷及其所有答案,每道题对应的分数也在这里头
class Answer {
	private int number;
	private String[] selfAnswer;// 二维数组用于左边是自己的答案,右边是对应的分数
	
	public Answer() {
		super();
	}

	public Answer(int t) {
		this.number = t;
	}
	
	public int getNumber() {
		return number;
	}

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

	public String getSelfAnswer(int i) {
		return selfAnswer[i];
	}
	
	public String[] getSelfAnswer() {
		return selfAnswer;
	}

	public void setSelfAnswer(String[] selfAnswer) {
		this.selfAnswer = selfAnswer;
	}
	
	
	
}

// 答卷类——封装一种卷子的多张答案
class AnswerSheet {
	private ArrayList<Answer> answer = new ArrayList<Answer>();// 存储多张答案
	
	public AnswerSheet() {
		super();
	}

	public ArrayList<Answer> getAnswer() {
		return answer;
	}

	public void setAnswer(ArrayList<Answer> answer) {
		this.answer = answer;
	}

	
}

  代码如上述所述,接着将对自己的源码进行分析。

  1.因为题目对于题目信息,试卷信息,答题信息的输入是乱序输入的,所以自己在放入题目前是先判断他是何种信息,采用contains函数,来确定放入何处。

  2.但是对于信息处理的不足之处是,所有信息的处理都放在了主方法。一个大的while循环 ,里面包含了所有的信息的读取与处理。对于日后的题目的迭代并不好修改以及阅读。

  3.然后再在后面一个遍历所有试卷的大循环之中,先找到对应的答卷。在里面我自己使用了choice1与choice2来判断是否找没找到 ,首先从变量的名字上来说,自己的命名就不很规范,应该是以found来表示更能增加可读性。其次自己大可以不必用两个变量来判断。一个足以,要是在遍历答卷的时候没找到就continue,然后遍历整个答卷found仍未false,那么便说明,这个没有找到。然后输出“The test paper number does not exist”便可以了。

  4.在上述的那个遍历所有试卷的大循环,这个部分代码数太长,应该拆成几部分:一是判断正误,二是存储分数,三是输出判断结果与与得分。而且这个部分也不应该是放在主方法中,主方法只进行信息的读入与输出。而不是对信息的处理。

根据SOURCEMONITIOR生成的情况来看:

根据数据与雷达图分析:

  • 分支语句占总语句数的百分比为 15%。仍然处于较低的水平
  • 方法调用语句数目为78,这次与上次相比增加很多,说明了这段代码的模块化程度比上次更高,但也是可能因为这段代码的难度比上次的更大的缘故。
  • 含有注释的行占比大幅度增大,上次只是1,6这次到了9.2,注释的增多,说明了代码的可读性也增强了。
  • 这段代码的平均深度与最大深度都比较大,可能就是因为我的while大循环与遍历试卷的大循环的缘故。
  • 每个方法的平均语句数量比较少,这一点与上面的点相映衬。要是上面的大循环被拆除同时化为其他小部分,那么这段代码就质量更高了。

(三)题目集三

题目一是对输入信息的简单读取并封装到类中,然后提取信息,以设置的格式输出出来。

题目二是要求我们对日期类的简单使用,对输入的日期进行验证和分析。首先,需要验证给定的日期是否为合法日期,然后判断该年是否为闰年,并计算该日期是当年第几天、当月第几天、当周第几天。接着,需要判断输入的起始日期和结束日期是否合法,同时结束日期是否早于起始日期。如果输入的日期全部合法且结束日期不早于起始日期,则输出日期之间的相差天数、月数和年数。如果有任何日期输入非法或结束日期早于起始日期,则输出相应的错误信息。

题目三是“答题判题程序-3”

设计实现答题程序,模拟一个小型的测试,以下粗体字显示的是在答题判题程序-2基础上增补或者修改的内容,要求输入题目信息、试卷信息、答题信息、学生信息、删除题目信息,根据输入题目信息中的标准答案判断答题的结果。

输入格式:

程序输入信息分种,信息可能会打乱顺序混合输入。

1、题目信息
题目信息为独行输入,一行为一道题,多道题可分多行输入。

格式:"#N:"+题目编号+" "+"#Q:"+题目内容+" "#A:"+标准答案

格式约束:
    1、题目的输入顺序与题号不相关,不一定按题号顺序从小到大输入。
    2、允许题目编号有缺失,例如:所有输入的题号为1、2、5,缺少其中的3号题。此种情况视为正常。
样例:#N:1 #Q:1+1= #A:2
     #N:2 #Q:2+2= #A:4

     
2、试卷信息

  试卷信息为独行输入,一行为一张试卷,多张卷可分多行输入数据。
格式:"#T:"+试卷号+" "+题目编号+"-"+题目分值+" "+题目编号+"-"+题目分值+...

格式约束:
   题目编号应与题目信息中的编号对应。
   一行信息中可有多项题目编号与分值。 
样例:#T:1 3-5 4-8 5-2   

     
3、学生信息

  学生信息只输入一行,一行中包括所有学生的信息,每个学生的信息包括学号和姓名,格式如下。

格式:"#X:"+学号+" "+姓名+"-"+学号+" "+姓名....+"-"+学号+" "+姓名     

格式约束:
    答案数量可以不等于试卷信息中题目的数量,没有答案的题目计0分,多余的答案直接忽略,答案之间以英文空格分隔。
 样例:
       #S:1 #A:5 #A:22
       1是试卷号 
       5是1号试卷的顺序第1题的题目答案 

4、答卷信息

  答卷信息按行输入,每一行为一张答卷的答案,每组答案包含某个试卷信息中的题目的解题答案,答案的顺序号与试 卷信息中的题目顺序相对应。答卷中:

格式:"#S:"+试卷号+" "+学号+" "+"#A:"+试卷题目的顺序号+"-"+答案内容+...

    

格式约束:
       答案数量可以不等于试卷信息中题目的数量,没有答案的题目计0分,多余的答案直接忽略,答案之间以英文空格分隔。
       答案内容可以为空,即””。
       答案内容中如果首尾有多余的空格,应去除后再进行判断。
样例:
       #T:1 1-5 3-2 2-5 6-9 4-10 7-3
       #S:1 20201103 #A:2-5 #A:6-4
       1是试卷号
       20201103是学号
       2-5中的2是试卷中顺序号,5是试卷第2题的答案,即T中3-2的答案 
       6-4中的6是试卷中顺序号,4是试卷第6题的答案,即T中7-3的答案 
注意:不要混淆顺序号与题号

 

5、删除题目信息

  删除题目信息为独行输入,每一行为一条删除信息,多条删除信息可分多行输入。该信息用于删除一道题目信息,题目被删除之后,引用该题目的试卷依然有效,但被删除的题目将以0分计,同时在输出答案时,题目内容与答案改为一条失效提示,例如:”the question 2 invalid~0”

格式:"#D:N-"+题目号

格式约束:

       题目号与第一项”题目信息”中的题号相对应,不是试卷中的题目顺序号。

       本题暂不考虑删除的题号不存在的情况。      
样例:
#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-5 2-8
#X:20201103 Tom-20201104 Jack
#S:1 20201103 #A:1-5 #A:2-4
#D:N-2
end

输出
alert: full score of test paper1 is not 100 points
1+1=~5~false
the question 2 invalid~0
20201103 Tom: 0 0~0

     答题信息以一行"end"标记结束,"end"之后的信息忽略。

输出格式:


1、试卷总分警示


该部分仅当一张试卷的总分分值不等于100分时作提示之用,试卷依然属于正常试卷,可用于后面的答题。如果总分等于100 分,该部分忽略,不输出。


格式:"alert: full score of test paper"+试卷号+" is not 100 points"

 样例:alert: full score of test paper2 is not 100 points


2、答卷信息


一行为一道题的答题信息,根据试卷的题目的数量输出多行数据。

格式:题目内容+"~"+答案++"~"+判题结果(true/false)

约束:如果输入的答案信息少于试卷的题目数量,答案的题目要输"answer is null"   
样例:
     3+2=~5~true
     4+6=~22~false.
     answer is null

     

3、判分信息

 判分信息为一行数据,是一条答题记录所对应试卷的每道小题的计分以及总分,计分输出的先后顺序与题目题号相对应。

    格式:**学号+" "+姓名+": "**+题目得分+" "+....+题目得分+"~"+总分

    格式约束:

     1、没有输入答案的题目、被删除的题目、答案错误的题目计0分
     2、判题信息的顺序与输入答题信息中的顺序相同

    样例:20201103 Tom: 0 0~0

       根据输入的答卷的数量以上2、3项答卷信息与判分信息将重复输出。

 
4、被删除的题目提示信息


当某题目被试卷引用,同时被删除时,答案中输出提示信息。样例见第5种输入信息“删除题目信息”。


5、题目引用错误提示信息


试卷错误地引用了一道不存在题号的试题,在输出学生答案时,提示”non-existent question~”加答案。例如:

输入:

#N:1 #Q:1+1= #A:2
#T:1 3-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103 #A:1-4
end

输出:
alert: full score of test paper1 is not 100 points
non-existent question~0
20201103 Tom: 0~0
如果答案输出时,一道题目同时出现答案不存在、引用错误题号、题目被删除,只提示一种信息,答案不存在的优先级最高,例如:
输入:
#N:1 #Q:1+1= #A:2
#T:1 3-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103
end

输出:
alert: full score of test paper1 is not 100 points
answer is null
20201103 Tom: 0~0


6、格式错误提示信息


输入信息只要不符合格式要求,均输出”wrong format:”+信息内容。

      例如:wrong format:2 #Q:2+2= #4

7、试卷号引用错误提示输出

 

如果答卷信息中试卷的编号找不到,则输出”the test paper number does not exist”,答卷中的答案不用输出,参见样例8。

 

8、学号引用错误提示信息


如果答卷中的学号信息不在学生列表中,答案照常输出,判分时提示错误。参见样例9。

 

本题暂不考虑出现多张答卷的信息的情况。

 

输入样例1:

简单输入,不含删除题目信息。例如:

#N:1 #Q:1+1= #A:2
#T:1 1-5
#X:20201103 Tom
#S:1 20201103 #A:1-5
end

输出样例1:

在这里给出相应的输出。例如:

alert: full score of test paper1 is not 100 points
1+1=~5~false
20201103 Tom: 0~0

输入样例2:

简单输入,答卷中含多余题目信息(忽略不计)。例如:

#N:1 #Q:1+1= #A:2
#T:1 1-5
#X:20201103 Tom
#S:1 20201103 #A:1-2 #A:2-3
end

输出样例3

简单测试,含删除题目信息。例如:

alert: full score of test paper1 is not 100 points
1+1=~2~true
20201103 Tom: 5~5

输入样例3:

简单测试,含删除题目信息。例如:

#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-5 2-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103 #A:1-5 #A:2-4
#D:N-2
end

输出样例3:

在这里给出相应的输出,第二题由于被删除,输出题目失效提示。例如:

alert: full score of test paper1 is not 100 points
1+1=~5~false
the question 2 invalid~0
20201103 Tom: 0 0~0

输入样例4:

简单测试,含试卷无效题目的引用信息以及删除题目信息(由于题目本身无效,忽略)。例如:

#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-5 3-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103 #A:1-5 #A:2-4
#D:N-2
end

输出样例4:

输出不存在的题目提示信息。例如:

alert: full score of test paper1 is not 100 points
1+1=~5~false
non-existent question~0
20201103 Tom: 0 0~0

输入样例5:

综合测试,含错误格式输入、有效删除以及无效题目引用信息。例如:

#N:1 +1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-5 2-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103 #A:1-5 #A:2-4
#D:N-2
end

输出样例5:

在这里给出相应的输出。例如:

wrong format:#N:1 +1= #A:2
alert: full score of test paper1 is not 100 points
non-existent question~0
the question 2 invalid~0
20201103 Tom: 0 0~0

输入样例6:

综合测试,含错误格式输入、有效删除、无效题目引用信息以及答案没有输入的情况。例如:

#N:1 +1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-5 2-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103 #A:1-5
#D:N-2
end

输出样例6:

答案没有输入的优先级最高。例如:

wrong format:#N:1 +1= #A:2
alert: full score of test paper1 is not 100 points
non-existent question~0
answer is null
20201103 Tom: 0 0~0

输入样例7:

综合测试,正常输入,含删除信息。例如:

#N:2 #Q:2+2= #A:4
#N:1 #Q:1+1= #A:2
#T:1 1-5 2-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103 #A:2-4 #A:1-5
#D:N-2
end

输出样例7:

例如:

alert: full score of test paper1 is not 100 points
1+1=~5~false
the question 2 invalid~0
20201103 Tom: 0 0~0

输入样例8:

综合测试,无效的试卷引用。例如:

#N:1 #Q:1+1= #A:2
#T:1 1-5
#X:20201103 Tom
#S:2 20201103 #A:1-5 #A:2-4
end

输出样例8:

例如:

alert: full score of test paper1 is not 100 points
The test paper number does not exist

 

输入样例9:

无效的学号引用。例如:

#N:1 #Q:1+1= #A:2
#T:1 1-5
#X:20201106 Tom
#S:1 20201103 #A:1-5 #A:2-4
end

输出样例9:

答案照常输出,判分时提示错误。例如:

alert: full score of test paper1 is not 100 points
1+1=~5~false
20201103 not found

输入样例10:

信息可打乱顺序输入:序号不是按大小排列,各类信息交错输入。但本题不考虑引用的题目在被引用的信息之后出现的情况(如试卷引用的所有题目应该在试卷信息之前输入),所有引用的数据应该在被引用的信息之前给出。例如:

#N:3 #Q:中国第一颗原子弹的爆炸时间 #A:1964.10.16
#N:1 #Q:1+1= #A:2
#X:20201103 Tom-20201104 Jack-20201105 Www
#T:1 1-5 3-8
#N:2 #Q:2+2= #A:4
#S:1 20201103 #A:1-5 #A:2-4
end

输出样例10:

答案按试卷中的题目顺序输出。例如:

alert: full score of test paper1 is not 100 points
1+1=~5~false
中国第一颗原子弹的爆炸时间~4~false
20201103 Tom: 0 0~0
对题目进行分析:
  此次增加了题目的迭代增加了学生的信息,以及删除题目的信息这两条信息。因此初步设计在上次的基础上增加学生类,以及对每个题目增加一条属性,用于判断这个题目删没被删除。
  题目输入:
  1.题目信息,试卷信息与上次相同。特别注意的是,因为并不是输入的每一道题目试卷都会引用,并且试卷引用的题目可能试题还没输入,因此我们增加questionBank类,用于存储所有的题目, 之后再组装试卷。
  2.学生信息。一行输入所有的学生的信息,包括他的学号与姓名。
  3.答卷信息,与上次大体上相同,但是增加了学号信息。
  4.删除题目信息,当删除后,遍历题目库,将对应的题目exist属性赋为false。
  题目输出:
  1.试卷总分警示
  2.答题信息-即根据试卷的题目的数量输出多行数据,其中被删除的信息要输出“the question 2 invalid~0”,试卷引用了一道不存在题号的试题则输出“non-existent question~0”
  3.格式错误,即上述输入的形式不按照 格式来,那么便输出“wrong format”+输入的信息。这个是最难办的,要
  4.还要注意,试卷号引用错误提示输出以及学号引用错误提示信息。
 
下面是自己的代码:
 
题目集三最后一题
 package one_seven_oop3_last;

import java.util.ArrayList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

 
public class Last3 {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		
		Controller controller = new Controller();
		
		String input = in.nextLine();
		while(!input.equals("end")) {
			
			if(input.matches("\\s*#N:\\s*\\d+\\s+#Q:\\s*[^#]*\\s*#A:.*")) {
				controller.inputN(input);
			}
			
			else if(input.matches("(#T:\\d+){1}(\\s+[0-9]+-[0-9]+){0,}\\s*")) {
				controller.inputT(input);
			}
			
			else if(input.matches("(\\s*#X:\\s*){1}(\\d+\\s+[^- ]+-){0,}(\\d+\\s+.+){1}\\s*")) {
				controller.inputX(input);
			}
			
			else if(input.matches("(\\s*#S:\\s*\\d+\\s+\\d+\\s*){1}(\\s*#A:\\s*\\d+-[^#]*){0,}\\s*")) {
				controller.inputS(input);
			}
						
			else if(input.matches("\\s*#D:\\s*N-\\s*\\d+\\s*")) {
				controller.inputD(input);
			}
			
			else {
				controller.view.wrongMenu(input);
			}
			
			input = in.nextLine();
		}
		
		// 组装试卷
		controller.composePaper();
		
		// 输出试卷不足100分警示信息
		controller.lackScoreOutput();
		
		controller.judgeAnswer();
		
		// 以下皆为测试代码
		// N
//		System.out.println(controller.getQuestionBank().getQuestion().get(0).getNumber());
//		System.out.println(controller.getQuestionBank().getQuestion().get(0).getContent());
//		System.out.println(controller.getQuestionBank().getQuestion().get(0).getStandAnswer());
		// T
//		System.out.println(controller.getTestPaper().get(0).getNumber());
//		System.out.println(controller.getTestPaper().get(0).getNumScore());
		// X
//		System.out.println(controller.getStudent().get(0).getId());
//		System.out.println(controller.getStudent().get(0).getName());
//		System.out.println(controller.getStudent().get(1).getId());
//		System.out.println(controller.getStudent().get(1).getName());
		// S
//		System.out.println(controller.getAnswerSheet().getAnswer().get(0).getNumber());
//		System.out.println(controller.getAnswerSheet().getAnswer().get(0).getId());
//		System.out.println(controller.getAnswerSheet().getAnswer().get(0).getNoAnswer().get(0)[0]);
//		System.out.println(controller.getAnswerSheet().getAnswer().get(0).getNoAnswer().get(0)[1]);
//		System.out.println(controller.getAnswerSheet().getAnswer().get(0).getNoAnswer().get(1)[0]);
//		System.out.println(controller.getAnswerSheet().getAnswer().get(0).getNoAnswer().get(1)[1]);
		// D
//		System.out.println(controller.getQuestionBank().getQuestion().get(1).isExist());
		// composePaper
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(0).getNumber());
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(0).getContent());
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(0).getScore());
//		
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(1).getNumber());
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(1).getContent());
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(1).getScore());
//		
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(2).getNumber());
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(2).getContent());
//		System.out.println(controller.getTestPaper().get(0).getQuestion().get(2).getScore());
	}
}

// 题目类
class Question {
	private int number;// 题目编号
	private String content = "bank";// 题目内容
	private String standAnswer;// 题目标准答案
	private int score;// 题目分数
	private boolean exist = false;// 判断题目删没被删除
	
	public Question() {
		super();
	}

	public Question(int number, boolean exist) {
		super();
		this.number = number;
		this.exist = exist;
	}

	public Question(int number, String content, String standAnswer, boolean exist) {
		super();
		this.number = number;
		this.content = content;
		this.standAnswer = standAnswer;
		this.exist = exist;
	}

	public Question(boolean exist) {
		this.exist = exist;
	}

	public int getNumber() {
		return number;
	}

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

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public String getStandAnswer() {
		return standAnswer;
	}

	public void setStandAnswer(String standAnswer) {
		this.standAnswer = standAnswer;
	}

	public int getScore() {
		return score;
	}

	public void setScore(int score) {
		this.score = score;
	}

	public boolean isExist() {
		return exist;
	}

	public void setExist(boolean exist) {
		this.exist = exist;
	}
	
}

// 题库类
class QuestionBank {
	private ArrayList<Question> question = new ArrayList<Question>();// 所有题目集合
	
	public QuestionBank() {
		super();
	}

	public ArrayList<Question> getQuestion() {
		return question;
	}

	public void setQuestion(ArrayList<Question> question) {
		this.question = question;
	}

}

// 试卷类
class TestPaper {
	private int number;// 试卷编号
	private ArrayList<Question> question = new ArrayList<Question>();// 一种试卷有多道题目
	private ArrayList<Integer[]> numScore = new ArrayList<Integer[]>();
	public TestPaper() {
		super();
	}

	public TestPaper(int number) {
		super();
		this.number = number;
	}

	public ArrayList<Question> getQuestion() {
		return question;
	}

	public void setQuestion(ArrayList<Question> question) {
		this.question = question;
	}

	public ArrayList<Integer[]> getNumScore() {
		return numScore;
	}

	public void setNumScore(ArrayList<Integer[]> numScore) {
		this.numScore = numScore;
	}

	public int getNumber() {
		return number;
	}

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

// 一张答卷类
class Answer {
	private int number; // 试卷号
	private String id;// 做题学生的学号
	private ArrayList<Integer[]> noScore = new ArrayList<Integer[]>();// 试卷中的顺序号与每道题目的得分
	private ArrayList<String[]> noAnswer = new ArrayList<String[]>();// 试卷中的顺序号与对应的自己的答案
	private StringBuilder info;// 存储一道题目要输出的信息
	private boolean exist = true;// 判断这张答卷的引的试卷的题号在不在,默认是true,也就是有
	
	public Answer() {
		super();
	}

	public Answer(int number, String id) {
		super();
		this.number = number;
		this.id = id;
	}

	public boolean isExist() {
		return exist;
	}

	public void setExist(boolean exist) {
		this.exist = exist;
	}

	public ArrayList<Integer[]> getNoScore() {
		return noScore;
	}

	public void setNoScore(ArrayList<Integer[]> noScore) {
		this.noScore = noScore;
	}

	public ArrayList<String[]> getNoAnswer() {
		return noAnswer;
	}

	public void setNoAnswer(ArrayList<String[]> noAnswer) {
		this.noAnswer = noAnswer;
	}

	public int getNumber() {
		return number;
	}

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

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public StringBuilder getInfo() {
		return info;
	}

	public void setInfo(StringBuilder info) {
		this.info = info;
	}
	
}

// 多张答卷类
class AnswerSheet {
	private ArrayList<Answer> answer = new ArrayList<Answer>();// 存储多张答案

	public AnswerSheet() {
		super();
	}

	public ArrayList<Answer> getAnswer() {
		return answer;
	}

	public void setAnswer(ArrayList<Answer> answer) {
		this.answer = answer;
	}

	
}

// 学生类
class Student {
	private String id;
	private String name;
	
	public Student(String id, String name) {
		super();
		this.id = id;
		this.name = name;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	
}

// 存储要输出的内容 ? && 定义不同的输入方式对应的方法
class Controller {
	// 题目库
	QuestionBank questionBank = new QuestionBank();
	// 试卷库
	ArrayList<TestPaper> testPaper = new ArrayList<TestPaper>();
	// 答卷库
	AnswerSheet answerSheet = new AnswerSheet(); 
	// 学生库
	ArrayList<Student> student = new ArrayList<Student>();
	
	View view = new View();
	
	public QuestionBank getQuestionBank() {
		return questionBank;
	}

	public void setQuestionBank(QuestionBank questionBank) {
		this.questionBank = questionBank;
	}

	public ArrayList<TestPaper> getTestPaper() {
		return testPaper;
	}

	public void setTextPaper(ArrayList<TestPaper> testPaper) {
		this.testPaper = testPaper;
	}

	public AnswerSheet getAnswerSheet() {
		return answerSheet;
	}

	public void setAnswerSheet(AnswerSheet answerSheet) {
		this.answerSheet = answerSheet;
	}

	public ArrayList<Student> getStudent() {
		return student;
	}

	public void setStudent(ArrayList<Student> student) {
		this.student = student;
	}

	public void inputN(String info) {
		Question q = null;
		// 分割问题
		String[] text = info.split("\\s*#N:\\s*|\\s*#Q:\\s*|\\s*#A:");
		if(text.length == 4) {
			if(text[3].equals("\\s+"))
				q = new Question(Integer.parseInt(text[1]),text[2],text[3],true);
			else {
				text[3] = text[3].trim();
				q = new Question(Integer.parseInt(text[1]),text[2],text[3],true);
			}	
		}
		if(text.length == 3) {
			q = new Question(Integer.parseInt(text[1]),text[2],"",true);
		}

		questionBank.getQuestion().add(q);
		
	}
	
	public void inputT(String info) {
		String[] texts = info.split("\\s*#T:\\s*|\\s+");// 第一次拆分
		TestPaper p = new TestPaper((Integer.parseInt(texts[1])));
		for(int i = 2; i < texts.length; i++) {
	        String text = texts[i];
	        String[] singleText = text.split("-");// 第二次拆分
	        // 传入每一题的分数
	        Integer[] numscore = new Integer[singleText.length];
	        for (int k = 0; k < singleText.length; k++) {
	            numscore[k] = Integer.parseInt(singleText[k]);
	        }
	        p.getNumScore().add(numscore);
	    }
		testPaper.add(p);
	}
	
	// 有个点没考虑,要是关于s的信息输入有错怎么办?
	public void inputX(String info) {
		String[] texts = info.split("\\s*#X:\\s*|-");
		for(int i = 1; i < texts.length; i++) {
			String text = texts[i];
			String[] singleText = text.split("\\s+");
			Student s = new Student(singleText[0], singleText[1]);
			student.add(s);
		}
	}	
	
	public void inputS(String info) {
		Answer a = null;
		// 分割前面的
		Pattern pattern = Pattern.compile("\\s*#S:\\s*\\d+\\s* \\d+\\s*");
        Matcher matcher = pattern.matcher(info);
        if(matcher.find()) {
        	String[] texts = matcher.group().split("\\s*#S:\\s*|\\s+");
    		a = new Answer(Integer.parseInt(texts[1]),texts[2]);
        }
		//分割后面的
        info = info.replaceAll("#S:\\d+\\s+\\d+\\s+", " ");
        String[] texts = info.split("\\s+#A:\\s*");
        for(int i = 1; i < texts.length;i++) {
        	String text = texts[i];
        	String[] singleText = text.split("#A:\\s*|-");
        	
        	// 防止答案输入为空,为空则为这一题答案变为null
		    String[] noAnswer = new String[3];
		    
		    if(singleText.length == 1) {
		    	noAnswer[0] = singleText[0];
		    	noAnswer[1] = " ";
		    }
		    else {
		    	noAnswer[0] = singleText[0];
			    noAnswer[1] = singleText[1];
		    }
		    a.getNoAnswer().add(noAnswer);
		    
		    Integer[] noScore = new Integer[2];
		    noScore[0] = Integer.parseInt(singleText[0]);
		    noScore[1] = 0;
		    a.getNoScore().add(noScore);
        }
        
//        String regex1 = "\\s+#A:\\s+\\d+-\\s*";
//        String regex2 = "#A:\\d+-\\s*\\S+.*?(?=\\s)";
//        String regex3 = "#A:\\d+-\\w+(\\s+\\w+)*";
//        pattern = Pattern.compile("#A:\\d+-\\w+(\\s+\\w+)*|#A:\\d+-\\s*");
//        matcher = pattern.matcher(info);
//        while (matcher.find()) {
//        	String text = matcher.group();
//        	String[] singleText = text.split("#A:|-");
//        	// 防止答案输入为空,为空则为这一题答案变为null
//		    String[] noAnswer = new String[3];
//		    if(singleText.length == 2) {
//		    	noAnswer[0] = singleText[1];
//		    	noAnswer[1] = "";
//		    }
//		    else {
//		    	noAnswer[0] = singleText[1];
//			    noAnswer[1] = singleText[2];
//		    }
//		    a.getNoAnswer().add(noAnswer);
//		    
//		    Integer[] noScore = new Integer[singleText.length];
//		    noScore[0] = Integer.parseInt(singleText[1]);
//		    noScore[1] = 0;
//		    a.getNoScore().add(noScore); 
//        }
        answerSheet.getAnswer().add(a);
	}

	public void  inputD(String info) {
		String[] texts = info.split("\\s*#D:N-\\s*");
		for(int i = 0; i < questionBank.getQuestion().size();i++) {
			if(questionBank.getQuestion().get(i).getNumber() == Integer.parseInt(texts[1]))
				questionBank.getQuestion().get(i).setExist(false);
		}
	}
	
	// 至此,所有信息都已放入该放的地方
	
	// 组装试卷(参数是题库,与试卷的集合)
	public void composePaper() {
		for(int i = 0; i < testPaper.size(); i++) {
			// 下面这个循环进入的是每张卷子-对于第i张卷子
			for(int j = 0; j < testPaper.get(i).getNumScore().size(); j++) {
				// 得到的是这张卷子的第j题的题号
				int num = testPaper.get(i).getNumScore().get(j)[0];
				Question q = new Question();
				// 遍历题库,若是可以找到就q赋值分数,然后跳出循环.如果找不到则found为0
				int found = 0;
				for(int k = 0; k < questionBank.getQuestion().size(); k++) {
					if(questionBank.getQuestion().get(k).getNumber() == num) {
						q = questionBank.getQuestion().get(k);
						q.setScore(testPaper.get(i).getNumScore().get(j)[1]);
						found = 1;
						break;
					}
				}
				// found == 0,那么也创建一个,同时只给这题目赋值题号
				// 若是日后,则判断他的题目是不是bank
				if(found == 0) {
					q.setNumber(num);
				}
				// 加进去题目
				testPaper.get(i).getQuestion().add(q);
			}
			
		}
	}
	
	// 输出试卷不足100分警示信息
	public void lackScoreOutput() {
		for(int i = 0; i < testPaper.size(); i++) {
			int cnt = 0;
			for(int j = 0; j < testPaper.get(i).getNumScore().size(); j++) {
				// 这里有个争议,就是要是一张卷子加一起满足100分,但是又被删除了一题,它后面是不是输出不是满分警示呢?
				if(testPaper.get(i).getQuestion().get(j).isExist() == true)
					cnt = cnt + testPaper.get(i).getQuestion().get(j).getScore();
			}
			if(cnt != 100) {
				view.alertMenu(i);
			}
		}
	}
	
	
	public void judgeAnswer() {
		// 遍历所有答题的卷子
		for(int i = 0; i < answerSheet.getAnswer().size(); i++) {
			// 找这张答卷对应的试卷p
			int number = answerSheet.getAnswer().get(i).getNumber();
			int paperFound = 0;
			TestPaper p = null;
			for(int w = 0; w < testPaper.size(); w++) {
				if(number == testPaper.get(w).getNumber()) {
					p = testPaper.get(w);
					paperFound = 1;
					break;
				}
			}
			// 判断找没找得到这张试卷
			if(paperFound == 0) {
				view.notExitPaperNumber();
				continue;
			}
			// 把临时p的分数变为0全部
			ArrayList<Integer[]> numScore0 = new ArrayList<Integer[]>();
			for(int j = 0; j < p.getQuestion().size(); j++) {				
					Integer noScore[] = {p.getNumScore().get(j)[0],0};
					numScore0.add(noScore);
			}
			// 得到了第i张答题卷子
			// j应当小于对应的试卷的题目数量,因为多的题目直接忽略-answerSheet.getAnswer().get(i).getNoAnswer().size()
			for(int j = 0; j < p.getQuestion().size(); j++) {
				// 得到对应试卷的第j个问题
				Question q = p.getQuestion().get(j);
				int questionFound = 0;
				int answerk = 0;
				for(int k = 0; k < answerSheet.getAnswer().get(i).getNoAnswer().size(); k++) {
					// 如果第j个问题==答卷的题号
					if(j+1 == answerSheet.getAnswer().get(i).getNoScore().get(k)[0]) {
						questionFound = 1;
						answerk = k;
						break;
					}
				}
				// 试卷的这一题在答卷中没找到
				if(questionFound == 0) {
					view.answerNullMenu();
					continue;
				}
				// 引用了错误题号
				if(q.getContent().equals("bank")){
					view.existentMenu();
					continue;
				}
				// 题目是被删除了的
				if(q.isExist() == false) {
					view.invalidMenu(j+1);
					continue;
				}

				// 得到这张卷子的对应的答案
				String selfAnswer = answerSheet.getAnswer().get(i).getNoAnswer().get(answerk)[1];
				if(selfAnswer.equals(q.getStandAnswer())) {
					Integer noScore[] = {p.getNumScore().get(j)[0],p.getNumScore().get(j)[1]};
					numScore0.set(j, noScore);
					System.out.println(q.getContent()+"~"+q.getStandAnswer()+"~true");
				}
				else {
					System.out.println(q.getContent()+"~"+selfAnswer+"~false");
				}						
			}
			int cnt = 0;
			int stuFound = 0;
			for(int j = 0; j < student.size(); j++) {
				if(student.get(j).getId().equals(answerSheet.getAnswer().get(i).getId())) {
					System.out.print(student.get(j).getId()+" "+student.get(j).getName()+":");
					stuFound = 1;
					break;
				}
			}
			if(stuFound == 0) {
				System.out.println(answerSheet.getAnswer().get(i).getId()+" not found");
				continue;
			}
			for(int j = 0; j < numScore0.size(); j++) {
				cnt = cnt + numScore0.get(j)[1];
				System.out.print(" "+numScore0.get(j)[1]);
			}
			System.out.println("~"+cnt);
		}
		
	}

	
}

// 存储输出类
class View  {
	
	public void wrongMenu(String info) {
		System.out.println("wrong format:"+info);
	}
	
	public void alertMenu(int i) {
		System.out.println("alert: full score of test paper"+ (i+1) + " is not 100 points");
	}
	
	public void notExitPaperNumber() {
		System.out.println("The test paper number does not exist");
	}
	
	public void answerNullMenu() {
		System.out.println("answer is null");
	}
	
	public void invalidMenu(int no) {
		System.out.println("the question "+(no)+" invalid~0");
	}
	
	public void existentMenu() {
		System.out.println("non-existent question~0");
	}
}

代码结构如图所示——

分析自己的代码:

1.主方法进行信息的读入:因为会有错误信息的输入所以要进行正则表达式的匹配,只是之前的contains是远不能足以胜任的。当输入的信息匹配这种模式的时候,才可能被读入,否则就输出出来。但是我的正则表达式太长太复杂了。可读性非常差,也不利于后面的代码的维护。

2.比上次好的是,增加了controller类,里面的各种方法来进行对信息的输入切割与处理判断。

3.controller来进行对nstxd的读入,以及组装试卷compose功能,judgeAnswer功能。降低了其他实体类之间的耦合度。

4.而view类则存放输出语句,提高代码的覆用性。

根据SOURCEMONITIOR生成的情况来看:

根据数据与雷达图分析:

  • 分支语句占总语句数的百分比为 14.2%。仍然处于较低的水平,保持。
  • 方法调用语句数目为131,这次与上次相比增加很多,说明了这段代码的模块化程度比上次更高,但也是可能因为这段代码的难度比上次的进一步更大的缘故。
  • 这段代码的平均深度与最大深度都比较适中
  • 每个方法的平均语句数量比较少,这一点估计是因为controller类中一个大循环干了很多功能的缘故。

 

三、踩坑心得

  1.在写第二次题目集的时候,自己其实写了两遍。第一遍的时候因为命名不规范,一个是题目编号,一个是题目序号,搞得比较乱,还有试卷与答卷内部属性的命名都非常地像,导致后面在那个遍历试卷的循环的时候,自己都看不懂自己的代码,很难再进行下去的时候,就花费了一两个小时重新把代码写了一遍,逻辑更加清晰,而且代码命名也得到了优化。
 
  2.在写第三次的代码的时候,起初对于题目输入的错误信息,想的太单纯了,以为只是只有题目信息会出输入形式错误,因此只是对题目信息的输入做了判断,实际上是所有的信息都会有可能是 错误的。因此自己将contains函数改成了matches函数,匹配题目要求的模式,否则的话就会认为是错误输入,这其中正则表达式的处理最为难办。
 
  3.在处理判断分数的那一节的时候,自己一开始用的是hashmap,因为想的是每一题正好对应每一个分数,但是hashmap是无序的,无法记录插入顺序,而且hashmap的key与value并不好遍历,在处理分数的时候,原本每一题分数的存储我是放在了answer里面,然后在判断对错的时候再将分数提取出来,对的给他赋值上原本的分数,否则就是为0。最后我是用了arraylist,还是它最香。
 
  4.有一个比较恶心的是我自己一开始题目没看清,不知道最后分数输出的顺序是按照试卷的顺序来进行输出的,我一开始是按照自己答题的顺序来进行输出,于是就呵呵呵了。所以导致最后的四个测试点老是不过,最终在那天晚上1点多的时候,经过再一次查看题目,改变我的分数输出顺序,oh year!终于一下子过了三个。
 

四、改进建议

  鉴于最后一题目是迭代的,所以我的最终的改进建议只是在最后一题的基础上提出改进想法

  1.在主方法中,修改掉那个大循环,只是读入一条语句,然后交由controller进行匹配,匹配到某种信息再进行切割。

  2.切割设置一个方法,用于不同类型的切割,也方便对后续的不同的切割类型进行继承。

  3.主类的形式大体不会改变,question存储单个题目信息,queationBank存储多个题目,构成题库,testPaper是对应的试卷。但是Answer由存储一个答卷改为存储一道答案,包括他的序号,答案,分数。为后续的增加多选题与填空题做准备。AnswerPaper是组装试题卷。

  4.对于大循环中,将主要只是进行遍历,判断的事情另写一个方法,交由那个方法,降低代码深度。

五、总结

终于啊。今天上从9点开始手打敲到了下午5点多!就只是今天的打字,还不算我之前的打字的数目,我的输入法就刚告诉我已经打了4931个字。好了言归正传。

这几次pta真的写的令我酣畅淋漓,令我等胆颤心惊。前一秒还大风卷我三重茅,举杯销愁愁更愁。后一秒就千树万树梨花开,一日看尽长安花了。

其实总结看来,现在回首,之前的题目也不是有多难。现在闭着眼睛都能把题目复述一遍。可能很大的情况就是畏难情绪,以及看到别人得到分了时候让你急躁。其余就只是自己的认真读懂题目 ,多读几遍,一定多读几遍,把需求看清了,然后按照需求来写!写错了大不了重新删了重新来过呗,也不是要死要活的,毕竟提升代码能力,锻炼设计能力才是正道!!然后平常注意休息,保持精神充沛,提高写代码时的专注度,也为自己日后某天猛熬夜做准备。

自己的边写边调试的习惯是蛮好的。当写完一个模块的时候,就自己调试验证他的正确性,保证代码的正确。

需要提升的就是自己的效率了,要是别人和我同时写代码,我可能要读题目理解题目,构思好长时间,而构思的程度也可能是和别人差不多的。所以这部分要加强。