答题判题程序
题目要求
设计实现答题程序,模拟一个小型的测试,要求输入题目信息、试卷信息、答题信息、学生信息、删除题目信息,根据输入题目信息中的标准答案判断答题的结果。
详见: 答题判题程序
前言
前两次作业较为的输入较为简单, 第一次还不支持乱序输入.
但第三次作业的难度就提升的挺多, 不仅支持乱序输入, 还添加了几种新的输入格式
写好这三次作业的关键是, 要构建出合适的类, 并处理好类和类之间的关系. 这样一来, 在复杂的输入情况下, 不容易把程序写乱.
由于这存在多个题目, 试卷, 答卷. 故我们需要使用合适的数据结构来存储这些数据. 在这里使用线性表, 哈希表都是可以的(分别对应java中的List(或数组), HashMap), 但博主认为使用线性表优于使用哈希表,原因如下:
-
在哈希表中, 每个键对应的值只有一个, 如果出现两张答卷的试卷号相同, 则哈希表中只能存储一张答卷.
而在使用线性表, 可以存储两个相同的元素.
-
哈希表中的元素都是无序的, 在输出时无法确保一个稳定的输出顺序, 而本题明显要求了有序的输出顺序
只有使用线性表, 才可以保证稳定有序的输出顺序
设计与分析
类的设计
此处的类为存储信息的必要类, 博主本人在做题时还创建了输入类, 输出类, 以及两个异常类
在写java程序时, 一定要设计好类和类之间的关系, 否则就发挥不出面向对象的优势. 而在设计类间关系时, 我们可以参考类所表示的事物在现实中的关系
在这道题目中, 主要有题目类, 试卷类, 答卷类, 学生类三种类. 根据它们在现实中的关系, 试卷应包含多道题目, 答卷应包含一个试卷, 及学生的学号. 故本题可以将题目类的对象作为试卷类的成员, 用list的方式在试卷中存储多道题目. 并将试卷类对象作为成员存储在答卷类中.
学生类
学生类包含学生的学号, 姓名, 以及一个用于存储读取到的学生的静态的list对象students
class Student {
private static List<Student> students = new ArrayList<>();
private String id;
private String name;
public Student(String id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
if(!(o instanceof Student)) {
return false;
}
return this.id.equals(((Student)o).id);
}
public static void addStudents(String str) {
str = str.substring(3);
String[] strs = str.split("-");
for(int i = 0; i < strs.length; i++){
Student.addStudent(strs[i]);
}
}
public static void addStudent(String str) {
String[] strs = str.split("\\s+");
String id = strs[0];
String name = strs[1];
Student student = new Student(id, name);
Student.students.add(student);
}
public static Student getStudentById(String id) {
for(Student s : Student.students) {
if(s.id.equals(id)) {
return s;
}
}
return null;
}
public static boolean hasStudent(String id) {
for(Student s : Student.students) {
if(s.id.equals(id)) {
return true;
}
}
return false;
}
@Override
public String toString() {
return this.id + " " + this.name;
}
}
题目类
题目类包含题目的题号、题目内容、标准答案以及用静态list对象存储所有读取到的题目
题目类中的valid
成员,表示题目是否有效,即是否被删除
题目类源码
class Question implements Comparable<Question>{
private int id;
private String content;
private String standardAnswer;
private boolean valid = true;
private static List<Question> questions = new ArrayList<>();
@Override
public int compareTo(Question q) {
return this.id - q.id;
}
public Question(int id, String content, String standardAnswer) {
this.id = id;
this.content = content;
this.standardAnswer = standardAnswer;
}
public boolean isValid() {
return this.valid;
}
public int getId() {
return id ;
}
public String getContent() {
return content;
}
public boolean judge(String answer) {
return answer.equals(this.standardAnswer);
}
public static void addQuestion(int id, String content, String standardAnswer) {
Question question = new Question(id, content, standardAnswer);
Question.questions.add(question);
}
public static Question getQuestion(int id) {
for(Question q : Question.questions) {
if(q.id == id) {
return q;
}
}
return null;
}
public static void removeQuestion(String str) {
str = str.substring(3).trim();
str = str.substring(2).trim();
int id = Integer.parseInt(str);
for(Question q : Question.questions) {
if(q.id == id) {
q.remove();
}
}
}
private void remove() {
this.valid = false;
}
}
添加题目
使用 addQuestion
方法添加题目, 题目将被添加到Question.questions
中
addQuestion
会被Input
类的inputQuestion
方法调用
删除题目
使用removeQuestion
方法删除题目, 但题目在questions
中并不是真正被删除了,而是将该题目中的valid
字段改为false
removeQuestion
方法先在questions
中找到要删除的题目,然后调用该题目的remove
方法
题目的remove
方法会将该题目的valid
成员设置为false
removeQuestion
会被Input
类的inputRemoveQuestion
方法调用
获取题目
使用getQuestion
方法获取题目,该方法传入要获取的题目的题号, 在questions
中找到题号对应的题目,然后返回该题目
getQuestion
方法会被TestPaper
类的addTestPaper
方法调用
判题
使用judge
方法判题, 使用时传入一个答案,如果与题目的标准答案相同,则返回true
, 否则返回false
试卷类
试卷类中包含该试卷号, 试卷中的题目(使用list存储), 题目对应的分值(用list存储), 以及用静态list对象testPapers
存储读取到的所有试卷
class TestPaper implements Comparable<TestPaper>{
private int id;
private List<Question> qs;
private List<Integer> scores;
private int size;
private static List<TestPaper> testPapers = new ArrayList<>();
public TestPaper(int id) {
this.qs = new ArrayList<>();
this.scores = new ArrayList<Integer>();
this.qs.add(null);
this.scores.add(null);
this.id = id;
}
public int getScore(int index) {
Question question = this.qs.get(index);
if(question == null || !question.isValid()) {
return 0;
}
return this.scores.get(index);
}
@Override
public int compareTo(TestPaper t) {
return this.id - t.id;
}
public void addQuestion(Question question, int score) {
this.qs.add(question);
this.scores.add(score);
this.size++;
}
public Question getQuestion(int index) {
return this.qs.get(index);
}
@Override
public boolean equals(Object o) {
return this.id == ((TestPaper)o).id;
}
public boolean judge(int index, String answer) {
Question question = this.qs.get(index);
if(question == null || answer == null) {
return false;
}
return question.judge(answer);
}
public int getSize() {
return this.size;
}
public int getId() {
return id;
}
public static void addTestPaper(String str) throws TotalScoreException {
str = str.substring(3);
String[] strs = str.split(" ");
int id = Integer.parseInt(strs[0]);
TestPaper testPaper = new TestPaper(id);
int sum = 0;
for(int i = 1; i < strs.length; i++) {
String[] tmp = strs[i].split("-");
int qid = Integer.parseInt(tmp[0]);
int score = Integer.parseInt(tmp[1]);
sum += score;
Question question = Question.getQuestion(qid);
testPaper.addQuestion(question, score);
}
TestPaper.testPapers.add(testPaper);
if(sum != 100) {
throw new TotalScoreException(id);
}
}
public static TestPaper getTestPaper(int id) {
for(TestPaper paper : TestPaper.testPapers) {
if(paper.id == id) {
return paper;
}
}
return null;
}
}
添加试卷
使用addTestPaper
方法添加试卷. 该方法会解析字符串中的试卷信息,然后将新试卷存到testPapers
里
在添加试卷的过程中,会计算试卷的总分,如果总分不是100分,则会抛出TotalScoreException
异常
获取试卷
getTestPaper
方法可以通过试卷号从testPaper
中获取试卷
getTestPaper
方法被Answer
类的构造方法调用
向试卷中添加题目
addQuestion
方法可以向试卷添加题目, 以及题目对应的分数
从试卷中获取题目
getQuestion
方法可以从试卷中获取题目
答卷类
答卷类中包含该答卷对应的试卷, 学生号, 各个题目的答案, 判题的结果
答卷类中还包含一个静态list对象answerPapers
, 用于存储读取到的所有答卷
class Student {
private static List<Student> students = new ArrayList<>();
private String id;
private String name;
public Student(String id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
if(!(o instanceof Student)) {
return false;
}
return this.id.equals(((Student)o).id);
}
public static void addStudents(String str) {
str = str.substring(3);
String[] strs = str.split("-");
for(int i = 0; i < strs.length; i++){
Student.addStudent(strs[i]);
}
}
public static void addStudent(String str) {
String[] strs = str.split("\\s+");
String id = strs[0];
String name = strs[1];
Student student = new Student(id, name);
Student.students.add(student);
}
public static Student getStudentById(String id) {
for(Student s : Student.students) {
if(s.id.equals(id)) {
return s;
}
}
return null;
}
public static boolean hasStudent(String id) {
for(Student s : Student.students) {
if(s.id.equals(id)) {
return true;
}
}
return false;
}
@Override
public String toString() {
return this.id + " " + this.name;
}
}
添加答卷
addAnswerPaper
方法用于添加答卷, 其被调用后,会解析字符串中的答卷信息,并将其存储到answerPapers
中
addAnswerPaper
方法会被Input
类的inputAnswerPaper
方法调用
判题
静态方法judgeAll
会为answerPapers
中的所有答卷进行判题, 即调用它们的非静态方法judge
非静态方法judge
会调用试卷类对象的judge
方法,然后将结果存储到答卷对象的results
中
类之间的关系
输入
可以创建一个输入类来进行输入
输入类
输入类中包含一个字符串列表inputs
, 用于存储所有输入
输入类中还包含5个字符串类型的正则表达式匹配模式, 用于匹配输入的是否合法,以及输入的类型
class Input {
public static List<String> inputs;
private static final String questionPattern = "^#N:(\\d+) #Q:(.+) #A:(.+)$";
private static final String testPaperPattern = "^#T:\\d+( \\d+-\\d+)+$";
private static final String answerPaperPattern = "^#S:\\d+ \\d+( #A:\\d+-[^#]*)*$"; //
private static final String StudentPattern = "^#X:(\\d+ \\S+)(-\\d+ \\S+)*$";
private static final String removeQuestionPattern = "^#D:N-(\\d+)$";
public Input() {
this.inputs = new ArrayList<>();
Scanner scanner = new Scanner(System.in);
while(scanner.hasNextLine()) {
String str = scanner.nextLine();
if(str.equals("end")) {
return;
}
this.inputs.add(str);
}
}
public void input() {
for(String str : this.inputs) {
try {
this.input(str.trim());
}catch(InputErrorException e) {
e.outputError();
}catch(TotalScoreException e) {
e.outputError();
}
}
AnswerPaper.judgeAll();
}
private void input(String str) throws TotalScoreException {
if(this.inputQuestion(str)) {
return;
}else if(this.inputTestPaper(str)) {
return;
}else if(this.inputAnswerPaper(str)) {
return;
}else if(this.inputRemoveQuestion(str)){
return;
}else if(this.inputStudent(str)) {
return;
}else {
throw new InputErrorException(str);
}
}
private boolean inputQuestion(String str) {
Pattern pattern = Pattern.compile(Input.questionPattern);
Matcher matcher = pattern.matcher(str);
if(!matcher.find()) {
return false;
}
int id = Integer.parseInt(matcher.group(1));
String content = matcher.group(2);
String answer = matcher.group(3);
Question.addQuestion(id, content, answer);
return true;
}
private boolean inputTestPaper(String str) throws TotalScoreException {
Pattern pattern = Pattern.compile(Input.testPaperPattern);
Matcher matcher = pattern.matcher(str);
if(!matcher.find()) {
return false;
}
TestPaper.addTestPaper(str);
return true;
}
private boolean inputAnswerPaper(String str){
Pattern pattern = Pattern.compile(Input.answerPaperPattern);
Matcher matcher = pattern.matcher(str);
if(!matcher.find()) {
return false;
}
AnswerPaper.addAnswerPaper(str);
return true;
}
private boolean inputRemoveQuestion(String str) {
Pattern pattern = Pattern.compile(Input.removeQuestionPattern);
Matcher matcher = pattern.matcher(str);
if(!matcher.find()) {
return false;
}
Question.removeQuestion(str);
return true;
}
private boolean inputStudent(String str) {
Pattern pattern = Pattern.compile(Input.StudentPattern);
Matcher matcher = pattern.matcher(str);
if(!matcher.find()) {
return false;
}
Student.addStudents(str);
return true;
}
}
具体过程
-
创建输入类
Input input = new Input();
创建输入类的过程中,输入类的构造方法会读取输入的字符串,将其存储在
Input.inputs
中public Input() { this.inputs = new ArrayList<>(); Scanner scanner = new Scanner(System.in); while(scanner.hasNextLine()) { String str = scanner.nextLine(); if(str.equals("end")) { return; } this.inputs.add(str); } }
-
调用输入类的
input
方法public void input() { for(String str : this.inputs) { try { this.input(str.trim()); }catch(InputErrorException e) { e.outputError(); }catch(TotalScoreException e) { e.outputError(); } } AnswerPaper.judgeAll(); } private void input(String str) throws TotalScoreException { if(this.inputQuestion(str)) { return; }else if(this.inputTestPaper(str)) { return; }else if(this.inputAnswerPaper(str)) { return; }else if(this.inputRemoveQuestion(str)){ return; }else if(this.inputStudent(str)) { return; }else { throw new InputErrorException(str); } }
无参数的input
会对每一行输入,分别调用有参数的input
. 无参数的input
方法会处理两种异常, 分别时总分不为100分的TotalScoreException
异常和输入格式错误的InputErrorException
异常. 针对这两种异常input
方法会输出不同的错误信息提示(符合题目要求的)
有参数的input
,会尝试将当前行的输入,解析为各种不同的信息,如果解析失败,则继续作为下一种信息解析.解析成功,则返回.
如果每种信息都无法解析成功,则input会抛出输入异常:InputErrorException
-
针对不同种信息的输入
-
输入题目
inputQuestion
方法用于输入题目private boolean inputQuestion(String str) { Pattern pattern = Pattern.compile(Input.questionPattern); Matcher matcher = pattern.matcher(str); if(!matcher.find()) { return false; } int id = Integer.parseInt(matcher.group(1)); String content = matcher.group(2); String answer = matcher.group(3); Question.addQuestion(id, content, answer); return true; }
inputQuestion
方法通过正则表达式的分组,获取到题目的题号, 题目内容, 题目标准答案.然后调用Question.addQuestion
方法, 添加题目-
输入试卷
inputTestPaper
方法用于输入试卷private boolean inputTestPaper(String str) throws TotalScoreException { Pattern pattern = Pattern.compile(Input.testPaperPattern); Matcher matcher = pattern.matcher(str); if(!matcher.find()) { return false; } TestPaper.addTestPaper(str); return true; }
inputTestPaper
方法会调用TestPaper
类的addTestPaper
方法, 该方法会解析出字符串中的试卷信息, 并同时计算该试卷的总分.如果试卷总分不为100分, 则会抛出TotalScoreException
异常.inputTestPaper
方法会将该异常继续抛出, 该异常在input
方法中进行处理 -
输入答卷
inputAnswerPaper
方法用于输入答卷private boolean inputAnswerPaper(String str){ Pattern pattern = Pattern.compile(Input.answerPaperPattern); Matcher matcher = pattern.matcher(str); if(!matcher.find()) { return false; } AnswerPaper.addAnswerPaper(str); return true; }
-
输入学生
input Student
方法用于输入学生private boolean inputStudent(String str) { Pattern pattern = Pattern.compile(Input.StudentPattern); Matcher matcher = pattern.matcher(str); if(!matcher.find()) { return false; } Student.addStudents(str); return true; }
-
输入删除题目信息
inputRemoveQuestion
方法用于输入删除题目信息private boolean inputRemoveQuestion(String str) { Pattern pattern = Pattern.compile(Input.removeQuestionPattern); Matcher matcher = pattern.matcher(str); if(!matcher.find() { return false; } Question.removeQuestion(str); return true; }
该方法会调用
Question
类的removeQuestion
方法, 用于删除题目.但此处的删除并不是真正的删除, 题目实际上还存在与题目列表里, 但题目的valid
字段被改成了false
, 表示该题目是一个无效的题目
-
输出
本题的输出主要分为两种: 错误信息输出和答卷信息输出
错误信息输出
错误信息输出主要是总分不为100时的提示, 格式错误提示, 题目不存在, 题目无效, 试卷不存在, 学生不存在.
其中总分不为100及格式错误提示, 在输入时已经以异常处理的方式进行输出了
而其他的错误信息输出, 则应当在答卷信息输出的同时进行输出
答卷信息输出
我们在List
中存储了多张答卷的信息, 现在我们只需要对这多张答卷分别进行输出
而对答卷输出, 则分为以下步骤:
- 检查试卷是否存在, 如果不存在, 输出试卷不存在错误提示, 输出结束
- 遍历试卷中的每一道题目, 若题目不存在或无效则输出相应错误提示, 题目存在则输出题目
- 检查学生是否存在, 若存在则输出学生信息和得分情况. 不存在则输出学生不存在错误提示
答卷类的toString
方法如下
@Override
public String toString() {
StringBuilder str = new StringBuilder();
if(this.testPaper == null) {
return "The test paper number does not exist";
}
for(int i = 1; i <= this.testPaper.getSize(); i++) {
if(i >= this.answers.size() || this.answers.get(i) == null) {
str.append("answer is null\n");
}else {
Question question = this.testPaper.getQuestion(i);
if(question == null) {
str.append("non-existent question~0").append("\n");
}else if (!question.isValid()) {
str.append("the question " + question.getId() + " invalid~0\n");
}else {
str.append(question.getContent() + "~" + this.answers.get(i)).append("~" + results.get(i)).append("\n");
}
}
}
Student student = Student.getStudentById(this.studentId);
if(student == null || !flag) {
str.append(this.studentId + " not found");
return str.toString();
}
str.append(student + "").append(": ");
int sum = 0;
for(int i = 1; i <= this.testPaper.getSize(); i++) {
if(i != 1) {
str.append(" ");
}
if(i >= this.answers.size()) {
str.append(0);
continue;
}
if(this.results.get(i)) {
str.append(this.testPaper.getScore(i));
sum += this.testPaper.getScore(i);
}else {
str.append(0);
}
}
str.append("~" + sum);
return str.toString();
}
完整源码
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args){
new Input().input();
new Output().output();
}
}
///////////////////////////////////////////////////
class Question implements Comparable<Question>{
private int id;
private String content;
private String standardAnswer;
private boolean valid = true;
private static List<Question> questions = new ArrayList<>();
@Override
public int compareTo(Question q) {
return this.id - q.id;
}
public Question(int id, String content, String standardAnswer) {
this.id = id;
this.content = content;
this.standardAnswer = standardAnswer;
}
public boolean isValid() {
return this.valid;
}
public int getId() {
return id ;
}
public String getContent() {
return content;
}
public boolean judge(String answer) {
return answer.equals(this.standardAnswer);
}
public static void addQuestion(int id, String content, String standardAnswer) {
Question question = new Question(id, content, standardAnswer);
Question.questions.add(question);
}
public static Question getQuestion(int id) {
for(Question q : Question.questions) {
if(q.id == id) {
return q;
}
}
return null;
}
public static void removeQuestion(String str) {
str = str.substring(3).trim();
str = str.substring(2).trim();
int id = Integer.parseInt(str);
for(Question q : Question.questions) {
if(q.id == id) {
q.remove();
}
}
}
private void remove() {
this.valid = false;
}
}
class TestPaper implements Comparable<TestPaper>{
private int id;
private List<Question> qs;
private List<Integer> scores;
private int size;
private static List<TestPaper> testPapers = new ArrayList<>();
public TestPaper(int id) {
this.qs = new ArrayList<>();
this.scores = new ArrayList<Integer>();
this.qs.add(null);
this.scores.add(null);
this.id = id;
}
public int getScore(int index) {
Question question = this.qs.get(index);
if(question == null || !question.isValid()) {
return 0;
}
return this.scores.get(index);
}
@Override
public int compareTo(TestPaper t) {
return this.id - t.id;
}
public void addQuestion(Question question, int score) {
this.qs.add(question);
this.scores.add(score);
this.size++;
}
public Question getQuestion(int index) {
return this.qs.get(index);
}
@Override
public boolean equals(Object o) {
return this.id == ((TestPaper)o).id;
}
public boolean judge(int index, String answer) {
Question question = this.qs.get(index);
if(question == null || answer == null) {
return false;
}
return question.judge(answer);
}
public int getSize() {
return this.size;
}
public int getId() {
return id;
}
public static void addTestPaper(String str) throws TotalScoreException {
str = str.substring(3);
String[] strs = str.split(" ");
int id = Integer.parseInt(strs[0]);
TestPaper testPaper = new TestPaper(id);
int sum = 0;
for(int i = 1; i < strs.length; i++) {
String[] tmp = strs[i].split("-");
int qid = Integer.parseInt(tmp[0]);
int score = Integer.parseInt(tmp[1]);
sum += score;
Question question = Question.getQuestion(qid);
testPaper.addQuestion(question, score);
}
TestPaper.testPapers.add(testPaper);
if(sum != 100) {
throw new TotalScoreException(id);
}
}
public static TestPaper getTestPaper(int id) {
for(TestPaper paper : TestPaper.testPapers) {
if(paper.id == id) {
return paper;
}
}
return null;
}
}
class AnswerPaper implements Comparable<AnswerPaper>{
private TestPaper testPaper;
private String studentId;
private boolean flag;
private List<String> answers;
private List<Boolean> results;
private static List<AnswerPaper> answerPapers = new ArrayList<>();
public static List<AnswerPaper> getAnswerPapers() {
return AnswerPaper.answerPapers;
}
@Override
public int compareTo(AnswerPaper a) {
return this.testPaper.getId() - a.testPaper.getId();
}
public AnswerPaper(int id, String studentId) {
this.answers = new ArrayList<>();
this.results = new ArrayList<>();
this.answers.add(null);
this.results.add(null);
TestPaper testPaper = TestPaper.getTestPaper(id);
this.testPaper = testPaper;
this.studentId = studentId;
}
public void addAnswer(int qid, String answer) {
int size = this.answers.size();
for(int i = 0; i < qid + 1 - size; i++) {
this.answers.add(null);
}
this.answers.set(qid, answer);
}
public static void judgeAll() {
for(AnswerPaper paper : AnswerPaper.answerPapers) {
paper.judge();
}
}
// 判断整张试卷
public void judge() {
if(this.testPaper == null) {
return;
}
for(int i = 1; i <= testPaper.getSize() && i < this.answers.size(); i++) {
this.results.add(testPaper.judge(i, this.answers.get(i)));
}
}
public static void addAnswerPaper(String str) {
str = str.substring(3);
String[] strs = str.split(" #A:");
String[] ids = strs[0].split(" ");
int id = Integer.parseInt(ids[0]);
String studentId = ids[1];
boolean flag = true;
if(!Student.hasStudent(studentId)) {
flag = false;
}
AnswerPaper answerPaper = new AnswerPaper(id, studentId);
answerPaper.flag = flag;
for(int i = 1; i < strs.length; i++) {
String[] tmp = strs[i].split("-");
int qid = Integer.parseInt(tmp[0]);
String answer = tmp.length >= 2 ? tmp[1] : "";
answerPaper.addAnswer(qid, answer);
}
AnswerPaper.answerPapers.add(answerPaper);
}
@Override
public String toString() {
StringBuilder str = new StringBuilder();
if(this.testPaper == null) {
return "The test paper number does not exist";
}
for(int i = 1; i <= this.testPaper.getSize(); i++) {
if(i >= this.answers.size() || this.answers.get(i) == null) {
str.append("answer is null\n");
}else {
Question question = this.testPaper.getQuestion(i);
if(question == null) {
str.append("non-existent question~0").append("\n");
}else if (!question.isValid()) {
str.append("the question " + question.getId() + " invalid~0\n");
}else {
str.append(question.getContent() + "~" + this.answers.get(i)).append("~" + results.get(i)).append("\n");
}
}
}
Student student = Student.getStudentById(this.studentId);
if(student == null || !flag) {
str.append(this.studentId + " not found");
return str.toString();
}
str.append(student + "").append(": ");
int sum = 0;
for(int i = 1; i <= this.testPaper.getSize(); i++) {
if(i != 1) {
str.append(" ");
}
if(i >= this.answers.size()) {
str.append(0);
continue;
}
if(this.results.get(i)) {
str.append(this.testPaper.getScore(i));
sum += this.testPaper.getScore(i);
}else {
str.append(0);
}
}
str.append("~" + sum);
return str.toString();
}
}
class Student {
private static List<Student> students = new ArrayList<>();
private String id;
private String name;
public Student(String id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
if(!(o instanceof Student)) {
return false;
}
return this.id.equals(((Student)o).id);
}
public static void addStudents(String str) {
str = str.substring(3);
String[] strs = str.split("-");
for(int i = 0; i < strs.length; i++){
Student.addStudent(strs[i]);
}
}
public static void addStudent(String str) {
String[] strs = str.split("\\s+");
String id = strs[0];
String name = strs[1];
Student student = new Student(id, name);
Student.students.add(student);
}
public static Student getStudentById(String id) {
for(Student s : Student.students) {
if(s.id.equals(id)) {
return s;
}
}
return null;
}
public static boolean hasStudent(String id) {
for(Student s : Student.students) {
if(s.id.equals(id)) {
return true;
}
}
return false;
}
@Override
public String toString() {
return this.id + " " + this.name;
}
}
class Input {
public static List<String> inputs;
private static final String questionPattern = "^#N:(\\d+) #Q:(.+) #A:(.+)$";
private static final String testPaperPattern = "^#T:\\d+( \\d+-\\d+)+$";
private static final String answerPaperPattern = "^#S:\\d+ \\d+( #A:\\d+-[^#]*)*$"; //
private static final String StudentPattern = "^#X:(\\d+ \\S+)(-\\d+ \\S+)*$";
private static final String removeQuestionPattern = "^#D:N-(\\d+)$";
public Input() {
this.inputs = new ArrayList<>();
Scanner scanner = new Scanner(System.in);
while(scanner.hasNextLine()) {
String str = scanner.nextLine();
if(str.equals("end")) {
return;
}
this.inputs.add(str);
}
}
public void input() {
for(String str : this.inputs) {
try {
this.input(str.trim());
}catch(InputErrorException e) {
e.outputError();
}catch(TotalScoreException e) {
e.outputError();
}
}
AnswerPaper.judgeAll();
}
private void input(String str) throws TotalScoreException {
if(this.inputQuestion(str)) {
return;
}else if(this.inputTestPaper(str)) {
return;
}else if(this.inputAnswerPaper(str)) {
return;
}else if(this.inputRemoveQuestion(str)){
return;
}else if(this.inputStudent(str)) {
return;
}else {
throw new InputErrorException(str);
}
}
private boolean inputQuestion(String str) {
Pattern pattern = Pattern.compile(Input.questionPattern);
Matcher matcher = pattern.matcher(str);
if(!matcher.find()) {
return false;
}
int id = Integer.parseInt(matcher.group(1));
String content = matcher.group(2);
String answer = matcher.group(3);
Question.addQuestion(id, content, answer);
return true;
}
private boolean inputTestPaper(String str) throws TotalScoreException {
Pattern pattern = Pattern.compile(Input.testPaperPattern);
Matcher matcher = pattern.matcher(str);
if(!matcher.find()) {
return false;
}
TestPaper.addTestPaper(str);
return true;
}
private boolean inputAnswerPaper(String str){
Pattern pattern = Pattern.compile(Input.answerPaperPattern);
Matcher matcher = pattern.matcher(str);
if(!matcher.find()) {
return false;
}
AnswerPaper.addAnswerPaper(str);
return true;
}
private boolean inputRemoveQuestion(String str) {
Pattern pattern = Pattern.compile(Input.removeQuestionPattern);
Matcher matcher = pattern.matcher(str);
if(!matcher.find()) {
return false;
}
Question.removeQuestion(str);
return true;
}
private boolean inputStudent(String str) {
Pattern pattern = Pattern.compile(Input.StudentPattern);
Matcher matcher = pattern.matcher(str);
if(!matcher.find()) {
return false;
}
Student.addStudents(str);
return true;
}
}
class Output {
public void output() {
for(AnswerPaper paper : AnswerPaper.getAnswerPapers()) {
System.out.println(paper);
}
}
}
class InputErrorException extends RuntimeException {
private String input;
public InputErrorException(String input) {
this.input = input;
}
public void outputError() {
System.out.println("wrong format:" + this.input);
}
}
class TotalScoreException extends RuntimeException {
private int id;
public TotalScoreException(int id) {
this.id = id;
}
public void outputError() {
System.out.println("alert: full score of test paper" + this.id + " is not 100 points");
}
}
踩坑心得
没有注意设计好输入顺序
刚开始在写这道题的时候, 并不是输入按照输入的顺序解析输入字符串的.我原先是先将所有输入的字符串都保存下来, 然后进行多次的解析. 第一次先将输入中的所有学生信息输入解析出来, 第二次将所有题目信息解析出来, 然后是删除题目信息, 试卷信息, 答卷信息
这是我第一次写的主函数, Input
为一个单例模式类, 在程序开始时就会创建出来, 创建时会读取输入的字符串
public static void main(String[] args){
Input.outputErrorInput();
Student.getStudents();
List<AnswerPaper> list = AnswerPaper.getAnswerPapers();
Question.removeQuestions();
TestPaper.checkSocre();
list.iterator().forEachRemaining(System.out::println);
}
我这样处理输入的一个很大的坏处就是, 改变的输入的顺序. 比如一张试卷引用了题号为2的题目, 但题号为2的题目在这张试卷后面才输出. 正常情况下应该时题目不存在的, 但我的程序却会判定题目存在
没有处理输入的前后空格
在处理每一行输入之前需要除去当前行的前后空格
改进建议
针对我当前的程序, 还有很多可以改进的地方. 主要时类和类之间的关系处理的不够好
答卷类和学生类的关系
当前我在答卷类中存储了一个字符串, 表示学生的学号. 实际上可以将学生类的对象作为成员存储在答卷类中
输入类和其他类的关系
目前我的程序, 输入类是起到了一定的作用, 可以组织输入, 并输出一些错误信息提示. 但还设计的不够好.
目前的输入类, 只是判定了输入是否合法及输入的类型, 并没有对输入字符串中的内容进行解析, 实际上还是将字符串传入各个类中的方法进行解析的. 比如下面输入试卷的方法
这样导致输入类和其他类之间的耦合度较高, 且输入类的内聚程度较低.
更好的做法是, 在输入类的方法中解析出字符串中的数据, 然后将这些数据传入各个类的方法中.
总结
在写这三次题目的过程中, 我学会了设计类, 及类与类之间的关系. 熟悉了ArrayList
的基本使用方法.