写在前面
1、基于2022级软件工程实验指导书
2、代码仅提供参考
3、如果代码不满足你的要求,请寻求其他的途径
运行环境
window11家庭版
IntelliJ IDEA 2023.2.2
jdk17.0.6
实验要求
任务:
一、构造任务4:批量产生习题并用文件存储。
二、构造任务6:批改练习并存储
三、构造任务5:生成100以内加法/减法的算式
以下为详细说明:
一、构造任务4:批量产生习题并用文件存储。
构造任务4.2.1:以第3章面向对象的版本为基础,完成构造任务4,建议新加一个类ExerciseFiles、增加方法,批量产生并存储习题(CSV文件格式)。
要求:
截屏和.txt文件,内容是CSV格式的练习题(20~50题),加、减、混合题各一套;
构造任务4.2.2:复用BinaryOperation, Exercise, ExerciseSheet,建议新加一个类ExerciseFiles、在其中增加方法,从CSV格式的文件中读入习题。
下面是4个CSV加法、减法练习文件,有的文件格式无任何多余符号、有的文件中有无关符号
文件1:exercise_add_50_1
文件2:exercise_add_70_2
文件3:exercise_sub_50_1
文件4:exercise_sub_60_2
要求:读入教师指定的上述4套CSV格式的练习文件并相应处理,按照3~5列:
2.1 屏幕显示读到的文件内容。
2.2 在上述基础上添加运算结果,例如33+22=55,屏幕显示,要求复用第三章的算式类;
技术考核点:
- 防御性编程
1.1 异常的使用和处理,比如不存在的文件、数值超出范围或者不满足约束条件;
1.2 练习文件中包含无关符号、要用正则表达式处理;
- junit的使用
2.1 测试异常,成功和失败各一次
2.2 参数化测试
2.3 测试套件
二、构造任务6:批改练习并存储。
练习结果以CSV格式写入一个练习文件;程序读入该文件,与相应习题中的每个算式答案比较;统计批改,屏幕显示,同时存入CSV格式的批改文件。练习结果文件的参考格式:
文件名:answers_add_50_19
76,65,61, 58,78,42,45,-1, 56, 63,...
要求练习答案的顺序和数目与对应的习题一致。对于没有做出的算式,录入到CSV文件时,用1表示。批改、统计练习后,存储文件的参考格式:
练习题:文件名
算式总数:50
正确:45
错误:5
得分:90
dd_50_3 exercise_add_50_3
Test2: answers_mix_70_3 exercise_ mix _70_3
功能考核点:
- 读入CSV格式的练习exercise文件,简单防御性处理:两者数量不一致,文件不存在,打不开文件(或者不是CSV格式);
屏幕输出读入的文件、截屏显示
- 从exercise中计算每一个算式的结果,要求复用第三章的算式类
屏幕输出每一个算式的结果、截屏显示
- 批改练习:检查结果是否正确,记录统计结果,屏幕输出或存入CSV格式的文件,给出证据
三、构造任务5:生成100以内加法/减法的算式基。
新加一个类BinaryOperationBase,产生算式基、存储到文件,从算式基随机选择算式组成练习,
考核点及验证:
- 分别生产正确的加法算式基、减法算式基;验证:2个截屏(数值范围可以是20)。
- 要求复用第三章的类,否则本题不得分。
加法算式基、减法算式基分别存入CSV格式的文件;
验证:CSV格式的2个文件。
从CSV格式的读入算式基、并分别组成一定数量练习;
验证:35道加法算式、48道减法算式,截屏。
- 把加法算式基和减法算式基合并在一个数据结构,存入CSV格式的文件,并且从中组成一定数量练习;验证:一个截屏和CSV格式的文件,50题混合算式的练习,截屏。
不完成3个任务、要求复用第三章的类,否则本题不得分。
源代码
BinaryOperation.java
import java.util.*;
abstract class BinaryOperation {
protected int operand1;
protected int operand2;
protected int result;
public BinaryOperation() {
// 生成操作数和计算结果
Random rand = new Random();
operand1 = rand.nextInt(101); // 生成0到100的随机数
operand2 = generateOperand2();
result = operate(operand1, operand2);
}
protected abstract int operate(int operand1, int operand2);
// 生成第二个操作数
protected abstract int generateOperand2();
public String getExpression() {
return operand1 + "\t" + getOperator() + "\t" + operand2 + "\t" + " = ";
}
protected abstract String getOperator();
public int getResult() {
return result;
}
}
// 加法类
class Addition extends BinaryOperation {
@Override
protected int operate(int operand1, int operand2) {
return operand1 + operand2;
}
@Override
protected int generateOperand2() {
Random rand = new Random();
return rand.nextInt(101 - operand1); // 第二个操作数不能超过100减去第一个操作数
}
@Override
protected String getOperator() {
return " + ";
}
}
// 减法类
class Subtraction extends BinaryOperation {
@Override
protected int operate(int operand1, int operand2) {
return operand1 - operand2;
}
@Override
protected int generateOperand2() {
Random rand = new Random();
return rand.nextInt(operand1 + 1); // 第二个操作数不能超过第一个操作数
}
@Override
protected String getOperator() {
return " - ";
}
}
Exercise.java
//构造要求2:实现Exercise
class Exercise {
private BinaryOperation operation;
public Exercise(BinaryOperation operation) {
this.operation = operation;
}
public String getExpression() {
return operation.getExpression();
}
public int getResult() {
return operation.getResult();
}
}
ExerciseSheet.java
import java.util.HashSet;
import java.util.Set;
//构造要求2:实现ExerciseSheet
class ExerciseSheet {
private Exercise[] exercises;
public ExerciseSheet(int numExercises, Class<? extends BinaryOperation> operationType) {
exercises = new Exercise[numExercises];
try {
Set<String> expressions = new HashSet<>(); // 使用集合来确保题目不重复
for (int i = 0; i < numExercises; i++) {
BinaryOperation operation = operationType.newInstance();
String expression = operation.getExpression();
// 如果集合中已经有了相同的表达式,则重新生成直到不重复为止
while (expressions.contains(expression)) {
operation = operationType.newInstance();
expression = operation.getExpression();
}
expressions.add(expression);
exercises[i] = new Exercise(operation);
}
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
public Exercise[] getExercises() {
return exercises;
}
}
ExerciseFIles.java
import java.io.*;
import java.util.Random;
//构造任务1:批量产生习题并用文件存储
public class ExerciseFiles {
private static final int NUM_EXERCISES = 50;
// 生成加法练习题并写入CSV文件
public static void generateAdditionCSV(String filename) {
generateCSV(filename, Addition.class);
}
// 生成减法练习题并写入CSV文件
public static void generateSubtractionCSV(String filename) {
generateCSV(filename, Subtraction.class);
}
// 生成加减混合练习题并写入CSV文件
public static void generateMixedOperationCSV(String filename) {
try (PrintWriter writer = new PrintWriter(new FileWriter(filename))) {
Random rand = new Random();
for (int i = 0; i < NUM_EXERCISES; i++) {
Class<? extends BinaryOperation> operationType = rand.nextBoolean() ? Addition.class : Subtraction.class;
ExerciseSheet sheet = new ExerciseSheet(1, operationType);
Exercise[] exercises = sheet.getExercises();
writer.println(exercises[0].getExpression());
}
System.out.println("CSV文件已生成:" + filename);
} catch (IOException e) {
e.printStackTrace();
}
}
// 生成CSV文件
private static void generateCSV(String filename, Class<? extends BinaryOperation> operationType) {
try (PrintWriter writer = new PrintWriter(new FileWriter(filename))) {
ExerciseSheet sheet = new ExerciseSheet(NUM_EXERCISES, operationType);
Exercise[] exercises = sheet.getExercises();
for (Exercise exercise : exercises) {
writer.println(exercise.getExpression());
}
System.out.println("CSV文件已生成:" + filename);
} catch (IOException e) {
e.printStackTrace();
}
}
// 读取并计算CSV文件中的算式
public static void calculateAndPrintCSV(String filename) {
try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
String line;
int count = 0; // 记录已输出的算式数量
while ((line = reader.readLine()) != null) {
// 对每一行数据进行预处理,去除可能存在的额外空格
line = line.trim().replaceAll("\\s+", "\t");
String[] parts = line.split("\t");
int operand1 = Integer.parseInt(parts[0]);
int operand2 = Integer.parseInt(parts[2]);
String operator = parts[1];
int result;
// 判断运算符并进行相应的计算
switch (operator) {
case "+":
result = operand1 + operand2;
break;
case "-":
result = operand1 - operand2;
break;
default:
System.out.println("警告:不支持的运算符:" + operator);
continue; // 跳过本次循环,继续处理下一个算式
}
// 输出算式及其结果
System.out.printf("%-10s", line + result + "\t\t");
count++;
if (count % 5 == 0) // 每行五个算式
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void generateAll() {
// 生成加法练习题CSV文件
ExerciseFiles.generateAdditionCSV("addition_exercises.csv");
// 生成减法练习题CSV文件
ExerciseFiles.generateSubtractionCSV("subtraction_exercises.csv");
// 生成加减混合练习题CSV文件
ExerciseFiles.generateMixedOperationCSV("mixed_operation_exercises.csv");
}
public static void calculateAndPrintAll() {
// 读取并计算加法练习题CSV文件
System.out.println("读取并计算加法练习题CSV文件:");
ExerciseFiles.calculateAndPrintCSV("addition_exercises.csv");
// 读取并计算减法练习题CSV文件
System.out.println("\n读取并计算减法练习题CSV文件:");
ExerciseFiles.calculateAndPrintCSV("subtraction_exercises.csv");
// 读取并计算加减混合练习题CSV文件
System.out.println("\n读取并计算加减混合练习题CSV文件:");
ExerciseFiles.calculateAndPrintCSV("mixed_operation_exercises.csv");
}
}
ExerciseCorrection.java
import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//构造任务2:批改练习并存储
public class ExerciseCorrection {
// 从文件中读取习题
private static List<String> readExercisesFromFile(String filename) throws IOException {
List<String> exerciseList = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
String line;
while ((line = reader.readLine()) != null) {
exerciseList.add(line);
}
}
return exerciseList;
}
// 获取用户输入的答案
private static List<Integer> getUserAnswers(List<String> exerciseList) {
List<Integer> userAnswers = new ArrayList<>();
Scanner scanner = new Scanner(System.in);
for (int i = 0; i < exerciseList.size(); i++) {
String exercise = exerciseList.get(i);
System.out.println("第 " + (i + 1) + " 题:" + exercise);
String userInput = scanner.nextLine();
try {
int answer = Integer.parseInt(userInput);
userAnswers.add(answer);
} catch (NumberFormatException e) {
userAnswers.add(-1);
}
}
return userAnswers;
}
// 写入用户答案到文件
private static void writeAnswersToFile(List<Integer> userAnswers, String filename) throws IOException {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) {
for (Integer answer : userAnswers) {
writer.write(answer + ",");
}
writer.newLine();
}
}
// 批改并统计结果
private static void correctAndReport(List<String> exerciseList, List<Integer> answersList, List<Integer> userAnswersList) {
int totalExercises = exerciseList.size();
if (totalExercises == 0 || answersList.size() == 0 || userAnswersList.size() == 0) {
System.out.println("习题文件或答案文件为空,请检查文件内容。");
return;
}
int correctCount = 0;
for (int i = 0; i < totalExercises; i++) {
int correctAnswer = evaluateExpression(exerciseList.get(i));
int userAnswer = userAnswersList.get(i);
if (userAnswer == correctAnswer) {
correctCount++;
}
}
// 统计结果
int incorrectCount = totalExercises - correctCount;
int score = (int) ((double) correctCount / totalExercises * 100);
System.out.println("算式批改结果已存入文件");
// 写入批改结果到文件
try (BufferedWriter writer = new BufferedWriter(new FileWriter("correction_results.csv"))) {
writer.write("练习题:" + "user_answers.csv");
writer.newLine();
writer.write("算式总数:" + totalExercises);
writer.newLine();
writer.write("正确:" + correctCount);
writer.newLine();
writer.write("错误:" + incorrectCount);
writer.newLine();
writer.write("得分:" + score);
} catch (IOException e) {
e.printStackTrace();
}
}
// 计算表达式的值
private static int evaluateExpression(String expression) {
// 使用正则表达式匹配数字和运算符,忽略不可见的空白字符
Pattern pattern = Pattern.compile("\\s*(\\d+)\\s*([-+])\\s*(\\d+)\\s*=\\s*");
Matcher matcher = pattern.matcher(expression);
if (matcher.matches()) {
int operand1 = Integer.parseInt(matcher.group(1));
String operator = matcher.group(2);
int operand2 = Integer.parseInt(matcher.group(3));
if (operator.equals("+")) {
return operand1 + operand2;
} else if (operator.equals("-")) {
return operand1 - operand2;
}
}
return 0;
}
public static void menu() {
Scanner scanner = new Scanner(System.in);
// 用户选择习题文件类型
System.out.println("请选择习题文件类型:");
System.out.println("1. 加法习题");
System.out.println("2. 减法习题");
System.out.println("3. 混合运算习题");
System.out.print("请选择:");
int choice = scanner.nextInt();
String exerciseFilename = "";
switch (choice) {
case 1:
exerciseFilename = "addition_exercises.csv";
break;
case 2:
exerciseFilename = "subtraction_exercises.csv";
break;
case 3:
exerciseFilename = "mixed_operation_exercises.csv";
break;
default:
System.out.println("无效选择。");
System.exit(-1);
}
String answersFilename = "user_answers.csv";
try {
List<String> exerciseList = readExercisesFromFile(exerciseFilename);
// 获取用户输入答案
List<Integer> userAnswersList = getUserAnswers(exerciseList);
// 写入用户答案到文件
writeAnswersToFile(userAnswersList, answersFilename);
// 从文件中读取正确答案
List<Integer> answersList = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new FileReader(answersFilename))) {
String line = reader.readLine();
if (line != null) {
String[] answersArray = line.split(",");
for (String answer : answersArray) {
answersList.add(Integer.parseInt(answer));
}
}
}
// 批改并统计结果
correctAndReport(exerciseList, answersList, userAnswersList);
} catch (IOException e) {
e.printStackTrace();
}
}
}
BinaryOperationBase.java
import java.io.*;
import java.util.*;
//构造任务3:生成100以内加法/减法的算式
public class BinaryOperationBase {
private List<String> additionBase;
private List<String> subtractionBase;
public BinaryOperationBase() {
this.additionBase = new ArrayList<>();
this.subtractionBase = new ArrayList<>();
}
// 生成加法算式基
public void generateAdditionBase(int numOperations) {
for (int i = 0; i < numOperations; i++) {
BinaryOperation addition = new Addition();
additionBase.add(addition.getExpression() + addition.getResult());
}
}
// 生成减法算式基
public void generateSubtractionBase(int numOperations) {
for (int i = 0; i < numOperations; i++) {
BinaryOperation subtraction = new Subtraction();
subtractionBase.add(subtraction.getExpression() + subtraction.getResult());
}
}
// 生成混合算式基
public void generateMixedOperationBase(int numOperations) {
generateAdditionBase(numOperations / 2);
generateSubtractionBase(numOperations / 2);
}
// 将加法算式基存储到文件
public void saveAdditionBaseToFile(String filename) {
saveBaseToFile(additionBase, filename);
}
// 将减法算式基存储到文件
public void saveSubtractionBaseToFile(String filename) {
saveBaseToFile(subtractionBase, filename);
}
// 将算式基存储到文件
private void saveBaseToFile(List<String> base, String filename) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) {
for (String operation : base) {
writer.write(operation);
writer.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 从加法算式基中随机选择指定数量的算式
public List<String> getRandomAdditionOperations(int numOperations) {
return getRandomOperations(additionBase, numOperations);
}
// 从减法算式基中随机选择指定数量的算式
public List<String> getRandomSubtractionOperations(int numOperations) {
return getRandomOperations(subtractionBase, numOperations);
}
// 从混合算式基中随机选择指定数量的算式
public List<String> getRandomMixedOperationOperations(int numOperations) {
List<String> mixedOperations = new ArrayList<>();
mixedOperations.addAll(additionBase);
mixedOperations.addAll(subtractionBase);
Collections.shuffle(mixedOperations);
return mixedOperations.subList(0, numOperations);
}
// 从算式基中随机选择指定数量的算式
private List<String> getRandomOperations(List<String> base, int numOperations) {
List<String> randomOperations = new ArrayList<>();
Random rand = new Random();
for (int i = 0; i < numOperations; i++) {
int index = rand.nextInt(base.size());
randomOperations.add(base.get(index));
}
return randomOperations;
}
public static void menu() {
BinaryOperationBase base = new BinaryOperationBase();
// 生成加法算式基并存储到文件
base.generateAdditionBase(100);
System.out.println("加法算式基已生成");
base.saveAdditionBaseToFile("addition_base.csv");
System.out.println("加法算式基已存入文件");
// 生成减法算式基并存储到文件
base.generateSubtractionBase(100);
System.out.println("减法算式基已生成");
base.saveSubtractionBaseToFile("subtraction_base.csv");
System.out.println("减法算式基已存入文件");
// 生成混合算式基并存储到文件
base.generateMixedOperationBase(100);
System.out.println("混合算式基已生成");
base.saveSubtractionBaseToFile("mixed_operation_base.csv");
System.out.println("混合算式基已存入文件");
// 从随机抽取的算式基中随机选择50个算式
List<String> randomAdditionOperations = base.getRandomAdditionOperations(50);
List<String> randomSubtractionOperations = base.getRandomSubtractionOperations(50);
List<String> randomMixedOperations = base.getRandomMixedOperationOperations(50);
// 将随机抽取的算式存入对应的CSV文件中
base.saveBaseToFile(randomAdditionOperations, "addition_exercises.csv");
base.saveBaseToFile(randomSubtractionOperations, "subtraction_exercises.csv");
base.saveBaseToFile(randomMixedOperations, "mixed_operation_exercises.csv");
}
}
Main.java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int choice = -1;
while (choice != 0) {
System.out.println("请输入你的选择:");
System.out.println("1、批量产生习题并用文件存储");
System.out.println("2、读入习题并添加答案");
System.out.println("3、批改练习并储存");
System.out.println("4、生成算式基并用文件储存");
System.out.println("0、退出");
System.out.printf("你的选择是:");
if (scanner.hasNextInt()) {
choice = scanner.nextInt();
switch (choice) {
case 1:
ExerciseFiles exerciseFiles = new ExerciseFiles();
exerciseFiles.generateAll();
break;
case 2:
ExerciseFiles exerciseFiles1 = new ExerciseFiles();
exerciseFiles1.calculateAndPrintAll();
break;
case 3:
ExerciseCorrection exerciseCorrection = new ExerciseCorrection();
exerciseCorrection.menu();
break;
case 4:
BinaryOperationBase binaryOperationBase = new BinaryOperationBase();
binaryOperationBase.menu();
break;
case 0:
System.out.println("程序已退出。");
break;
default:
System.out.println("无效的选项,请重新输入。");
break;
}
} else {
System.out.println("输入无效,请重新输入数字选项。");
scanner.next(); // 消耗无效输入
}
}
}
}