pta答题判断程序总结blog
一、前言
本次blog是针对发布题目集1~3的的最后一题的总结。三次大作业都是模拟一个小型的在线测试系统,先由大作业1完成基本功能,后面进行迭代,不断增加功能,丰富功能。下面具体分析这三次大作业的关键点和区别。
1、答题程序-1
1)输入:题目数量:首先输入题目数量。题目信息:按指定格式输入题目和标准答案。答题信息:记录学生的解答,格式约定答案顺序与题目顺序相对应。
2)实现了最基础的答题判题功能,主要输入题目信息和答题信息,并根据题目数量和答案进行判分。题目数量与答题信息的数量必须一致。
3) 关键点:利用正则表达式和字符串的拆分,解析出题目和答题信息。然后对每个题目判断学生的答案是否与标准答案一致,并输出 true 或 false,最后根据判题结果输出答题信息和判分信息。
2、答题程序-2
1)输入:题目信息:输入题目编号、内容和标准答案。试卷信息:增加试卷的编号和题目编号、分值。答卷信息:记录学生的答卷信息,并判分。
2)在程序-1的基础上,增加了试卷的概念。输入的顺序可以打乱,题目信息、试卷信息和答题信息可以混合输入。支持题目编号缺失的情况,程序仍正常处理。
3) 关键点:利用正则表达式和字符串的拆分,解析出题目、答题和试卷的信息。首先检查试卷总分是否为100分,不等于100分则输出警示。对每道题目进行判断,并根据答案输出 true 或 false。支持输出答题信息缺失提示 answer is null。根据每道题的分值计算学生的总分。
3、答题程序-3
1)输入:题目信息:管理题目编号、内容、标准答案。试卷信息:包含题目编号和分值,引用题目必须有效。学生信息:记录学号和姓名,答卷中学号需对应。删除题目信息:支持删除某道题目,并在答卷输出中标明题目失效。答卷信息:记录学生答题和学号。
2)在程序-2的基础上增加了学生信息管理。支持删除题目的功能,处理题目删除后试卷中对应题目失效的情况。增加了多种输入格式的错误提示,增强了系统的健康性。
3) 关键点:利用正则表达式和字符串的拆分,解析出题目、答题、试卷、学生和删除的信息。删除的题目会输出 the question X invalid 并计0分。引用不存在的题目提示 non-existent question。检查试卷总分不等于100分时输出警示。学号不在学生列表中提示学号引用错误,但答题照常输出。如果答卷信息中试卷的编号找不到,则输出”the test paper number does not exist”。输入信息只要不符合格式要求,均输出”wrong format:”+信息内容。如果答案输出时,一道题目同时出现答案不存在、引用错误题号、题目被删除,只提示一种信息,答案不存在的优先级最高。
二、设计分析
设计合理简洁的结构图可以使代码编写变得简便,因此这部分对三次答题程序的结构、变量、方法进行分析,分别画出他们的类图的顺序图。
1、答题程序-1
1)类图
答题程序1主要由以下几个类组成:
Question:表示单个题目,包含题号、题目内容和标准答案。
TestPaper:存储题目列表,并提供方法添加和管理题目。
AnswerSheet:存储用户的回答信息,对照标准答案进行判题和结果输出。
2)顺序图
下图展示了输入题目、答题和判题输出的流程。
3)主函数
主函数通过依次输入题目数量、题目内容、答案信息,调用evaluate方法判题并输出结果。代码结构清晰,主函数直接与TestPaper和AnswerSheet进行交互。
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 输入题目数量
int questionCount = Integer.parseInt(scanner.nextLine().trim());
TestPaper testPaper = new TestPaper();
// 输入题目内容
for (int i = 0; i < questionCount; i++) {
String line = scanner.nextLine().trim();
String[] parts = line.split(" #");
int number = Integer.parseInt(parts[0].replace("#N:", "").trim());
String content = parts[1].replace("#Q:", "").trim(); // 去掉"Q:"
String standardAnswer = parts[2].replace("#A:", "").trim();
testPaper.addQuestion(new Question(number, content, standardAnswer));
}
// 输入答题信息
AnswerSheet answerSheet = new AnswerSheet(testPaper);
String answerLine;
while (!(answerLine = scanner.nextLine().trim()).equals("end")) {
String[] answerParts = answerLine.replace("#A:", "").trim().split(" ");
for (String answer : answerParts) {
answerSheet.addAnswer(answer);
}
}
// 判题
answerSheet.evaluate();
// 输出结果
answerSheet.printResults();
scanner.close();
}
}
2、答题程序-2
1)类图
答题程序2在输入结构上有所扩展,引入了Agent类集中处理输入信息。
Agent:新增的输入管理类,包含题目、试卷和答卷的解析方法。
Question、Test和Answer类与程序1类似。
2)顺序图
顺序图显示了主函数如何通过Agent解析不同的输入类型,统一判题并输出结果。
3)主函数
由于输入较为复杂,相比程序1,答题程序2将输入处理逻辑移至Agent类中,使主函数的逻辑更简洁。这种设计将输入解析、判题、输出集中管理,便于代码扩展和维护。
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Agent agent = new Agent(); // 创建题目和试卷的管理类
while (scanner.hasNextLine()) {
String input = scanner.nextLine().trim();
if (input.equals("end"))
break;
if (input.startsWith("#N:")) {
agent.Questioninput(input); // 解析题目输入
} else if (input.startsWith("#T:")) {
agent.Testinput(input); // 解析试卷输入
} else if (input.startsWith("#S:")) {
agent.Answerinput(input); // 解析答卷输入
}
}
// 对所有答卷进行判题并输出结果
agent.printresult();
}
}
3、答题程序-3
1)类图
在程序2的基础上,答题程序3增加了学生信息管理和题目删除功能:
Agent:扩展了学生和删除操作的解析方法。
2)顺序图
顺序图展示了主函数如何调用Agent的多种输入解析方法和最终的判题输出。
3)主函数
与程序2类似,程序3的Agent类进一步扩展,允许解析学生信息、删除题目。这使程序适合更复杂的应用场景,但保持主函数的逻辑依然简洁。每种输入类型都通过专门的方法解析,增强代码的模块化。
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Agent agent = new Agent();
while (scanner.hasNextLine()) {
String input = scanner.nextLine().trim();
if (input.equals("end")) {
break;
} else if (input.startsWith("#N:")) {
agent.parseQuestionInput(input);
} else if (input.startsWith("#T:")) {
agent.parseTestInput(input);
} else if (input.startsWith("#X:")) {
agent.parseStudentInput(input);
} else if (input.startsWith("#S:")) {
agent.parseAnswerInput(input);
} else if (input.startsWith("#D:")) {
agent.parseDeleteInput(input);
}
}
agent.printResult();
}
}
总结
三个程序的设计逐步增加了系统复杂度,且在结构上不断优化:
程序1:较为简单的设计,直接在主函数中控制逻辑。
程序2:通过Agent类的引入,实现输入解析的模块化,使得代码更易于扩展。
程序3:在Agent类中增加了对学生信息和删除操作的支持,适合多功能应用需求。
这些设计的类图和顺序图展示了各自的输入、处理和输出流程,并为后续代码实现提供了清晰的设计指引。
三、踩坑心得
这部分对大作业中遇到的错误进行总结,在第一部分总结的关键点中,有很多编程时容易遇到很多错误。
1、答题程序-1
1)拆分字符串出现问题
情况描述:本题需要解析出题目#N和答题#A,总是不能解析到正确的题目和答题。输入格式非常严格,空格也会影响解析结果。
解决方法:由于为本行输入,所以需要多次用到分隔符split;去除空格的影响,再多次使用trim()。
如:解析题目内容函数如下,多次使用了分隔符和trim(),去除空格影响。
// 输入题目内容
for (int i = 0; i < questionCount; i++) {
String line = scanner.nextLine().trim();
String[] parts = line.split(" #");
int number = Integer.parseInt(parts[0].replace("#N:", "").trim());
String content = parts[1].replace("#Q:", "").trim(); // 去掉"Q:"
String standardAnswer = parts[2].replace("#A:", "").trim();
testPaper.addQuestion(new Question(number, content, standardAnswer));
}
2)题目和答题信息顺序不一致
情况描述:在实现评分功能时,我发现题号顺序和答题顺序不匹配会导致判分出错。例如,题库的题号为 1, 2, 3, 4,而答卷中题目顺序为 3, 2, 1, 4。
解决方法:判断是否正确是,不要按顺序处理,而是根据题号来进行对比。
public Question getQuestionByNumber(int number) {
for (Question question : questions) {
if (question.getNumber() == number) {
return question;
}
}
return null;
}
2、答题程序-2
1)试卷中缺少题目或题号不一致
情况描述:由于本题中,试卷题目缺失,试卷仍然有效,因此需要再答题程序1基础上进行改进。
解决方法:根据题目编号来查找题目,而不按照解析出的顺序,如果出现没有题目的答案,输出提示信息。
public void printresult() {
for (Answer answerSheet : answers) {
Test test = findTest(answerSheet.testNumber);
if (test != null) {
String result = test.grade(answerSheet, questions);
System.out.println(result);
}
}
}
2)各种输入情况出现时,输出顺序出错。
情况描述:乱序输入+分值不足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
3+2=5true
2+2=22false
7 0~7
alert: full score of test paper2 is not 100 points
2+2=5false
1+1=4false
answer is null
0 0 0~0
解决方法:需要格外注重输出的顺序,先将两张试卷的是否满100分情况先输出。作业才能得到预期输出结果。
alert: full score of test paper1 is not 100 points
alert: full score of test paper2 is not 100 points
3+2=5true
2+2=22false
7 0~7
2+2=5false
1+1=4false
answer is null
0 0 0~0
3、答题程序-3
1)无效的试卷引用,需要输出”the test paper number does not exist”
情况描述:当输入
N:1 #Q:1+1= #A:2
T:1 1-5
X:20201103 Tom
S:2 20201103 #A:1-5 #A:2-4
end
结果输出值显示了alert: full score of test paper1 is not 100 points
解决方法:新增试卷号,进行答卷判断是,要根据试卷号进行检查,然后没有该试卷号,要输出提示信息。
public Test findTest(int testNumber) {
for (Test test : tests) {
if (test.testNumber == testNumber) {
return test;
}
}
return null;
}
2)无效的学生引用,学号不在学生列表中提示学号引用错误,但答题照常输出。
举例:输入:
N:1 #Q:1+1= #A:2
T:1 1-5
X:20201106 Tom
S:1 20201103 #A:1-5 #A:2-4
end
预期输出:
alert: full score of test paper1 is not 100 points
1+1=5false
20201103 not found
解决方法:用try...catch捕获,学号不存在时,答题照常输出并进行判题,最后输出提示信息学号不存在。
public void parseStudentInput(String input) {
try {
input = input.substring(3);
String[] studentParts = input.split("-");
for (String studentInfo : studentParts) {
String[] parts = studentInfo.trim().split(" ");
if (parts.length == 2) {
String studentId = parts[0].trim();
String studentName = parts[1].trim();
students.put(studentId, studentName);
} else {
System.out.println("wrong format: " + input);
return;
}
}
} catch (Exception e) {
System.out.println("wrong format: " + input);
}
}
3)如果答案输出时,一道题目同时出现答案不存在、引用错误题号、题目被删除,只提示一种信息,答案不存在的优先级最高。
举例:含错误格式输入、有效删除、无效题目引用信息以及答案没有输入的情况。输入:
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
预期输出:
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
解决方法:新增错误信息集合,并设置错误信息优先级。
4)删除信息等多种复杂情况的输入时,需要注意输出顺序,以及对所有输入信息均要检验,不符合输入的均要输出提示信息。
四、改进建议
三次大作业的答题程序都没有满分,因此程序还有很多问题,还存在很大的进步空间。
1、答题程序-1
需要解决当答题数量小于题目数量情况时,输出错误的问题。
2、答题程序-2
需要优化混合输入的解析顺序,正确捕获需要的信息。在处理各种判断情况时,应该清晰编写判断函数。输出函数。
3、答题程序-2
需要解决无效的学生引用,学号不在学生列表中提示学号引用错误,答题不能照常输出的问题和输出信息优先级。Agent类中方法功能较多,可以考虑增加Student类,将相关代码放入,让整体框架更为简洁。本题存储答卷、学生等信息是使用list的,可以考虑使用动态方法,如动态数组、链表等方法。题目涉及删除学生信息,还可以考虑增删改查功能。
总而言之,在通过更多测试样例的前提下,不断清晰整体框架,改进解析输入方法和输出信息方法,之后再考虑向其他功能的改进。
五、总结
java语言程序设计是本学期才开设的课程,所以接触java语法时间较短。为了完成这三次答题程序的迭代,需要用到很多没有接触的java语句、语法。虽然遇到很多的问题、错误,但也让我学习到了很多东西。最让我印象深刻的便是三次答题程序的输入解析,面对大量的输入信息,正则表达式可以快速帮我们进行匹配,分隔符split可以快速帮我们进行分组,帮助我们提取到正确的输入信息。面对这种大量信息需要处理的程序时,编写时,一定要先将结构划分清楚,明确有哪些类,哪些功能,类与类之间的关系,这样能使编程更加简单。同时,通过这三次大作业,我意识到方法和变量合理、简单命名的重要性。一个简单、一眼知晓函数功能可以让我们梳理代码逻辑、检查代码错误时事半功倍,省事省力。同时,为了代码的健壮性,我们应该在代码中多设置一下输入输出提示,并注意他们的位置,达到既不凌乱又能给人提示的目的。通过这三个复杂的程序设计,我不仅熟悉了正则表达式,也掌握了各种java语法,熟悉了输入输出语句,了解存储结构arrary、arraylist、list等的使用,类的封装、调用规则。总而言之,虽然这三次程序设计难度很大,遇到很多问题,但也让我收获满满。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)