结对项目(JAVA)

结队项目:自动生成小学四则运算题目(JAVA)

 

一、Github项目地址(合作人:黄煜淇、郭沛)

  https://github.com/huange7/arithmetic


二、题目叙述

2.1题目数字以及运算符要求:

  • 真分数:1/2, 1/3, 2/3, 1/4, 1’1/2, …。
  • 自然数:0, 1, 2, …。
  • 运算符:+, −, ×, ÷。
  • 括号:(, )。
  • 等号:=。
  • 分隔符:空格(用于四则运算符和等号前后)。
  • 算术表达式:

    e = n | e1 + e2 | e1 − e2 | e1 × e2 | e1 ÷ e2 | (e),

    其中e, e1和e2为表达式,n为自然数或真分数。

  • 四则运算题目:e = ,其中e为算术表达式。

 2.2 生成题目具体操作过程及格式:

  • 使用 -n 参数控制生成题目的个数,例如: Myapp.exe -n 10 将生成10个题目。
  • 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如 :Myapp.exe -r 10 将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然数。该参数必须给定,否则程序报错并给出帮助信息。
  • 生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1− e2的子表达式,那么e1≥ e2。
  • 生成的题目中如果存在形如e1÷ e2的子表达式,那么其结果应是真分数。
  • 每道题目中出现的运算符个数不超过3个。
  • 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,23 + 45 = 和45 + 23 = 是重复的题目,6 × 8 = 和8 × 6 = 也是重复的题目。3+(2+1)和1+2+3这两个题目是重复的,由于+是左结合的,1+2+3等价于(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+3和3+2+1是不重复的两道题,因为1+2+3等价于(1+2)+3,而3+2+1等价于(3+2)+1,它们之间不能通过有限次交换变成同一个题目。
  • 生成的题目存入执行程序的当前目录下的Exercises.txt文件,格式如下:
  1. 四则运算题目1
  2. 四则运算题目2

   ……

   其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。

  • 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:

     答案1

     答案2

  • 真分数的运算如下例所示:1/6 + 1/8 = 7/24。
  • 程序应能支持一万道题目的生成。
  • 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,输入参数如下:

    Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt  统计结果输出到文件Grade.txt,格式如下: 

    Correct: 5 (1, 3, 5, 7, 9)

    Wrong: 5 (2, 4, 6, 8, 10)

    其中“:”后面的数字5表示对/错的题目的数量,括号内的是对/错题目的编号。为简单起见,假设输入的题目都是按照顺序编号的符合规范的题目。


三、解题思路

    1、首先是生成题目的实现思路:(伪代码如下) 

    步骤:
    if 随机方法
    { 
      随机生成操作符数量 operatorsNumber
      计算括号上限数量 limit
      随机生成数字 List<String> numberList
      随机生成运算符 List<Character>
    }
    for 
    if 满足括号条件 && 未达到括号数量上限
    if 随机方法
    左括号添加
    数字添加
    if 满足括号条件 && 括号数量大于0
    if 随机方法
    右括号添加
    运算符添加
    endfor
    将未闭合的括号进行闭合

    2、其次,得到一个表达式后,便开始对其进行计算,实现思路如下:

  • 将表达式中的所有真分数转换成假分数;
  • 将中缀表达式转化成后缀表达式,转换过程利用了栈的先进后出的特点;
  • 之后便是后缀表达式的计算过程:从左到右遍历中缀表达式中的每一个数字和符号;若是数字则进栈;若为符号,则把栈顶的两个数字出栈,进行运算(两个数运算过程见下方叙述),运算结果再进栈,直到获得最终结果;
  •  两个数运算过程:首先判断两个数是否为分数形式,若为分数形式则调用分数计算的方法,整数则对应整数的运算方法;在处理除号运算时,若分母为0,则会返回ERROR字符串;

  • 最后的计算结果若为负数或者计算的结果超出用户要求的限定范围,则也会返回ERROR字符串;

四、设计实现过程

 主要分成几个大类:Main、Service、ShowGraphic、Calculate以及AnswerFile,具体流程图如下:

  


 五、关键代码说明

 Main函数:

复制代码
public class Main {
    public static void main(String[] args) {
        Service service = new ServiceImpl();
        service.main(args);
    }

}
复制代码

ServiceImpl类:实现参数校验、调用GUI界面功能以及计算等核心功能

复制代码
public class ServiceImpl implements Service {

    private List<String> answerList = new ArrayList<>();

    public static List<LinkedList<String>> numberList = new ArrayList<>();

    public static List<LinkedList<Character>> charList = new ArrayList<>();

    @Override
    public void generateQuestion(Integer number) {
        // 清空答案列表
        answerList.clear();
        Operations operations = new Operations();
        int times = 0;
        while (number > 0) {
            AnswerResult answerResult = new AnswerResult();
            String operation = operations.generateOperations();
            String resultString = Calculate.getResult(operation, ArgsUtil.numberBound);
            if ("ERROR".equals(resultString)) {
                numberList.remove(numberList.size() - 1);
                charList.remove(charList.size() - 1);
                continue;
            }
            if (checkExpression(resultString)){
                numberList.remove(numberList.size() - 1);
                charList.remove(charList.size() - 1);
                times++;
                if (times == 16){
                    System.out.println("生成题目时冲突多次!");
                    break;
                }
                continue;
            }
            answerResult.setQuestion(operation + " =");
            answerList.add(resultString);
            Controller.operationData.add(answerResult);
            number--;
        }

        if (!ArgsUtil.isX) {
            // 将题目展示在控制台
            System.out.println("-----------------------------------------");
            printQuestion();
        }

        // 将答案写到文件
        try {
            AnswerFile.writeFile(answerList, true);
        } catch (IOException e) {
            System.out.println("生成答案文件异常");
        }

        System.out.println("答案文件已经存放在:" + AnswerFile.address);

        if (!ArgsUtil.isX) {
            downloadQuestion();
        }
    }

    private boolean checkExpression(String result){

        if (answerList.size() <= 0){
            return false;
        }

        int now = answerList.size();

        boolean flag = false;

        // 获取当前表达式
        List<String> nowNumber = numberList.get(now);
        List<Character> nowChar = charList.get(now);

        for (int i = 0; i < answerList.size() - 1; i++){
            if (!result.equals(answerList.get(i))){
                continue;
            }
            List<String> iNumber = numberList.get(i);
            List<Character> iChar = charList.get(i);

            // 如果数字的大小和字符的大小相等,则进行进一步的验证
            if (!(iNumber.size() == nowNumber.size() && iChar.size() == nowChar.size())){
                continue;
            }

            boolean bs = false;

            // 查看是否存在
            for (String iString : iNumber){
                if (!nowNumber.contains(iString)){
                    bs = true;
                    break;
                }
            }

            if (bs){
                continue;
            }

            for (Character iC : iChar){
                if (!nowChar.contains(iC)){
                    bs = true;
                    break;
                }
            }

            if (bs){
                continue;
            }

            flag = true;
        }

        return flag;
    }


    private void printQuestion() {
        Controller.operationData.forEach(answerResult -> {
            System.out.println(answerResult.questionProperty().getValue());
            System.out.println("-----------------------------------------");
        });
    }

    @Override
    public int[] checkQuestion() {
        File exerciseFile = new File(ArgsUtil.questionPath);
        File answerFile = new File(ArgsUtil.answerPath);
        Map<Integer, String> result = AnswerFile.checkAnswer(exerciseFile, answerFile);
        if (result == null){
            System.out.println("文件不存在!");
            return null;
        }
        int right = 0, error = 0;
        String Right = "";
        String Error = "";
        for (int i = 1; i <= result.size(); i++) {
            if (result.get(i).equals("right")) {
                right++;
                if (Right.equals("")) {
                    Right = Right + i;
                }
                else {
                    Right = Right + ", " + i;
                }
            }
            else {
                error++;
                if (Error.equals("")) {
                    Error = Error + i;
                }
                else {
                    Error = Error + ", " + i;
                }
            }
        }
        System.out.println("Correct: " + right + "(" + Right + ")" +"
" +  "Wrong: " + error + "(" + Error + ")");
        return new int[]{right, error};
    }

    @Override
    public void downloadQuestion() {
        // 生成题目文件
        try {
            AnswerFile.writeFile(Controller.operationData, false);
        } catch (IOException e) {
            System.out.println("生成题目文件时失败");
        }
        System.out.println("题目文件已经存放在:" + AnswerFile.address);
    }

    @Override
    public void main(String[] args) {
        // 进行参数的校验
        if (!ArgsUtil.verifyArgs(args, false)) {
            System.out.println("参数输入错误!");
            return;
        }

        // 展开图形界面
        if (ArgsUtil.isX) {
            ShowGraphic.show(args);
            return;
        }

        // 进行处理
        if (ArgsUtil.isGenerate) {
            // 生成题目
            generateQuestion(ArgsUtil.questionNumber);
        }else {
            // 进行答案的校对
            checkQuestion();
        }
    }
}
复制代码

Operation实现算术表达式的生成

复制代码
public class Operations {
    // 记录运算符数量
    private Integer operatorsNumber;

    // 记录括号的位置
    private List<Integer> bracketsPos = new ArrayList<>();

    // 括号最大值
    private static final Integer MAX_BRACKETS = 2;

    // 括号已结束
    private static final Integer USED = -1;

    // 记录已经使用的运算符数量
    private int count = 0;

    // 括号的限制数量
    private int limit = 0;

    // 存储数字
    private LinkedList<String> numberList;

    // 存储符号
    private LinkedList<Character> characters;


    public String generateOperations() {

        StringBuffer stringBuilder = new StringBuffer();

        if (randomSelective()) {
            init(true);
        }else {
            init(false);
        }

        Iterator<String> iteratorNumber = numberList.iterator();
        Iterator<Character> iteratorChar = characters.iterator();

        for (int i = 0; ; i++) {
            if (i % 2 == 0) {
                generateLeftBracket(stringBuilder);
                stringBuilder.append(iteratorNumber.next());
            } else {
                generateRightBracket(stringBuilder, false);
                stringBuilder.append(iteratorChar.next());
                count++;
            }
            if (!iteratorNumber.hasNext()) {
                break;
            }
            stringBuilder.append(" ");
        }

        generateRightBracket(stringBuilder, true);

        destroy();

        return stringBuilder.toString();
    }

    private void init(Boolean isTrueFraction) {
        // 随机生成操作符数量
        operatorsNumber = new Random().nextInt(3) + 1;

        // 设置括号的上限数量
        limit = operatorsNumber == 3 ? 2 : operatorsNumber == 1 ? 0 : 1;

        // 随机生成数字
        generateNumber(isTrueFraction);

        // 随机生成操作符
        generateChar();

        ServiceImpl.numberList.add(numberList);

        ServiceImpl.charList.add(characters);
    }

    private void destroy() {
        // 对数字进行归零
        operatorsNumber = 0;

        // 对括号位置进行置零
        bracketsPos.clear();

        // 对操作符数量进行置零
        count = 0;

        // 对括号上限进行置零
        limit = 0;
    }

    // 随机生成数字(整数或真分数)
    private void generateNumber(Boolean isTrueFraction) {
        numberList = new LinkedList<>();
        for (int i = 0; i < operatorsNumber + 1; i++) {
            numberList.add(buildNumber(isTrueFraction));
        }
    }

    private String buildNumber(Boolean isTrueFraction) {
        if (isTrueFraction && randomSelective()) {
            // 保证生成大于0
            int left;
            do {
                left = new Random().nextInt(ArgsUtil.numberBound);
            }while (left <= 0);
            // 控制分母在10以内
            int mother;
            do{
                mother = new Random().nextInt(ArgsUtil.numberBound < 11 ? ArgsUtil.numberBound : 11);
            }while (mother <= 0);
            int son;
            // 保证生成最简分数
            do {
                son = new Random().nextInt(mother) + 1;
            }while (!isSimplest(son, mother));
            return left + "'" + son + "/" + mother;
        } else {
            return String.valueOf(new Random().nextInt(ArgsUtil.numberBound));
        }
    }

    // 求出最简分数
    private boolean isSimplest(int son, int mother){
        int tempMo = mother, tempSon = son;
        int r = tempMo % tempSon;
        while ( r > 0){
            tempMo = tempSon;
            tempSon = r;
            r = tempMo % tempSon;
        }
        return tempSon == 1;
    }

    // 随机生成运算符
    private void generateChar() {
        characters = new LinkedList<>();
        String chars = "+-×÷";
        for (int i = 0; i < operatorsNumber; i++) {
            characters.add(chars.charAt(new Random().nextInt(chars.length())));
        }
    }

    // 随机选择算法
    private boolean randomSelective() {
        return new Random().nextInt(2) == 1;
    }

    // 生成左括号
    private void generateLeftBracket(StringBuffer stringBuilder) {
        for (int i = 0; i < limit; i++) {
            if (bracketsPos.size() >= limit) {
                break;
            }
            if (count >= operatorsNumber) {
                break;
            }
            if (count == 0 || (stringBuilder.charAt(stringBuilder.length() - 1) < '0' ||
                    stringBuilder.charAt(stringBuilder.length() - 1) > '9')) {
                if (!bracketsPos.isEmpty() && count - bracketsPos.get(0) > 1) {
                    break;
                }
                if (!bracketsPos.isEmpty() && count == bracketsPos.get(0) && bracketsPos.get(0) == operatorsNumber - 1) {
                    break;
                }
                // 随机算法-true则为加上括号
                if (randomSelective()) {
                    stringBuilder.append('(');
                    bracketsPos.add(count);
                }
            }
        }
    }

    // 生成右括号
    // flag 表示是否为表达式结尾
    private void generateRightBracket(StringBuffer stringBuilder, boolean flag) {
        if (bracketsPos.isEmpty()) {
            return;
        }

        if (flag) {
            // 如果已经到达结尾位置,进行剩余括号的闭括号操作
            for (int i = 0; i < bracketsPos.size(); i++) {
                if (!bracketsPos.get(i).equals(USED)) {
                    stringBuilder.append(')');
                }
            }
            // 可能发生多加一个括号的情况,将其进行剔除
            if (bracketsPos.size() == MAX_BRACKETS && bracketsPos.get(0).equals(bracketsPos.get(1)) && bracketsPos.get(0) != -1) {
                stringBuilder.delete(stringBuilder.length() - 1, stringBuilder.length());
            }
            return;
        }

        if (bracketsPos.size() == MAX_BRACKETS) {
            // 说明此时有两个括号
            if (bracketsPos.get(0).equals(bracketsPos.get(1))) {
                // 说明此时起始位置一样
                if (count - bracketsPos.get(1) == 1) {
                    // 说明此时内括号应该结束
                    stringBuilder.append(')');
                } else if (count - bracketsPos.get(0) == operatorsNumber - 1) {
                    // 说明此时内括号应该结束
                    stringBuilder.append(')');
                    bracketsPos.replaceAll(pos -> USED);
                }
            } else {
                // 说明起始位置不同
                if (count - bracketsPos.get(1) == 1) {
                    stringBuilder.append("))");
                    bracketsPos.replaceAll(pos -> USED);
                }
            }
        } else {
            if (count - bracketsPos.get(0) == operatorsNumber - 1) {
                stringBuilder.append(')');
                bracketsPos.set(0, -1);
                return;
            }
            if (count - bracketsPos.get(0) == 1) {
                if (randomSelective()) {
                    stringBuilder.append(')');
                    bracketsPos.set(0, -1);
                }
            }

        }
    }
}
复制代码

Calculate实现具体的计算过程

复制代码
public class Calculate {

    public static Pattern pattern = Pattern.compile("[0-9]+\'[0-9]+\/[1-9][0-9]*");

    //scope就是用户输入的范围限制
    public static String getResult(String expression, Integer scope) {

        //将所有空格去掉
        expression = expression.replaceAll(" +", "");
        //将表达式中所有的真分数转化成假分数
        Matcher m = pattern.matcher(expression);
        while(m.find())
        {
            expression = expression.replace(m.group(), Transform.TrueToFalse(m.group()));
        }
        //将中缀表达式转换成后缀表达式
        expression = Transform.change(expression);

        //对后缀表达式进行运算

        //存放操作符的栈
        Stack<String> stack = new Stack<>();

        //将后缀表达式进行切割,分成多个字符串,分割之后就是单纯的数字或者运算符
        String[] strings = expression.split("\|+");

        for (int i = 0; i < strings.length;) {
            if (strings[i].matches("[0-9].*")) {
                stack.push(strings[i]);
                i++;
                continue;
            }
            String num2 = stack.pop();
            String num1 = stack.pop();
            String result = cout(num1, num2, strings[i]);
            if (result.equals("ERROR")) {
                return result;
            }
            stack.push(result);
            i++;
        }
        //使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围
        String result = Transform.FinalFraction(stack.pop());
        if (result.equals("ERROR")) {
            return result;
        }
        //对结果进行校验
        if (Transform.isOutRange(scope, result)) {
            return "ERROR";
        }
        return result;
    }



    //判断两个数需要进行计算的方法:num1表示数字1,num2表示数字2,temp表示运算符,
    private static String cout(String num1, String num2, String temp) {

        String result;
        //分两种方式运算,一种是整数的运算,一种是分数的运算
        if (num1.matches("\-{0,1}[0-9]+\/\-{0,1}[0-9]+") || num2.matches("\-{0,1}[0-9]+\/\-{0,1}[0-9]+")) {
            //说明是分数,调用分数运算方法
            result = FractionCount(num1, num2, temp);
        }
        else {
            //调用整数运算方法
            result = IntCount(num1, num2, temp);
        }
        return result;
    }

    //num1表示数字1,num2表示数字2,temp表示运算符
    private static String IntCount(String num1, String num2, String temp) {
        switch (temp) {
            case "+":
                return String.valueOf(Integer.valueOf(num1) + Integer.valueOf(num2));
            case "-":
                return String.valueOf(Integer.valueOf(num1) - Integer.valueOf(num2));
            case "×":
                return String.valueOf(Integer.valueOf(num1) * Integer.valueOf(num2));
            case "÷":
                return Simplify(Integer.valueOf(num1), Integer.valueOf(num2));
                default:
        }
        return null;
    }

    //将分数进行化简的式子(numerator为分子,denominator为分母)
    public static String Simplify(Integer numerator, Integer denominator) {

        if (denominator == 0) {
            return "ERROR";
        }
        if (numerator == 0) {
            return "0";
        }
        int p = Transform.getMax(numerator, denominator);
        numerator /= p;
        denominator /= p;
        if (denominator == 1) {
            return String.valueOf(numerator);
        }
        else {
            return (numerator) + "/" + (denominator);
        }
    }



    //分数运算:num1表示数字1,num2表示数字2,temp表示运算符
    private static String FractionCount(String num1, String num2, String temp) {
        //将所有的数字都化成最简分数来进行计算
        int[] first = Transform.changeToFraction(num1);
        int[] second = Transform.changeToFraction(num2);
        int[] result = new int[2];
        //获取两个分母的最小公倍数
        int min = first[1] * second[1] / Transform.getMax(first[1], second[1]);
        switch (temp) {
            case "+":
                //分子
                result[0] = first[0] * min / first[1] + second[0] * min / second[1];
                //分母
                result[1] = min;
                return Simplify(result[0], result[1]);
            case "-":
                //分子
                result[0] = first[0] * min / first[1] - second[0] * min / second[1];
                //分母
                result[1] = min;
                return Simplify(result[0], result[1]);
            case "×":
                //分子
                result[0] = first[0] * second[0];
                //分母
                result[1] = first[1] * second[1];
                return Simplify(result[0], result[1]);
            case "÷":
                //分子
                result[0] = first[0] * second[1];
                //分母
                result[1] = first[1] * second[0];
                return Simplify(result[0], result[1]);
        }
        return null;
    }


}
复制代码

AnswerFile实现题目以及答案文本生成,同时进行答案校对的功能

复制代码
public class AnswerFile {
    //获取系统当前路径
    public static final String address = System.getProperty("user.dir");

    public static Pattern patten = Pattern.compile("[1-9][0-9]*\.[0-9]+(\'{0,1}[0-9]+\/[0-9]+){0,1}(\/[1-9]+){0,1}");

    //将答案写入文件
    public static void writeFile(List answerList, boolean isAnswer) throws IOException {
        File answerfile;
        File exercisefile;
        FileOutputStream outputStreamAnswer = null;
        FileOutputStream outputStreamExercise = null;
        BufferedWriter answerWriter = null;
        BufferedWriter exerciseWriter = null;
        if (isAnswer) {
            answerfile = new File(address + "\answer.txt");
            outputStreamAnswer = new FileOutputStream(answerfile);
            answerWriter = new BufferedWriter(new OutputStreamWriter(outputStreamAnswer, "UTF-8"));
            if (!answerfile.exists()) {
                answerfile.createNewFile();
            }
        } else {
            exercisefile = new File(address + "\exercise.txt");
            outputStreamExercise = new FileOutputStream(exercisefile);
            exerciseWriter = new BufferedWriter(new OutputStreamWriter(outputStreamExercise, "UTF-8"));
            if (!exercisefile.exists()) {
                exercisefile.createNewFile();
            }
        }
        int num = 1;
        for (Object o : answerList) {
            String answer;
            if (o instanceof String) {
                answer = (String) o;
            } else {
                answer = ((AnswerResult) o).questionProperty().getValue();
            }
            answer = num++ + ". " + answer + "
";
            if (isAnswer){
                answerWriter.write(answer);
                answerWriter.flush();
            }else {
                exerciseWriter.write(answer);
                exerciseWriter.flush();
            }
        }
        if (isAnswer){
            outputStreamAnswer.close();
            answerWriter.close();
        }else {
            outputStreamExercise.close();
            exerciseWriter.close();
        }
    }

    //答案校对,返回的是比对结果,key是题号,value是right或error
    public static Map<Integer, String> checkAnswer(File exercisefile, File answerFile) {

        Controller.operationData.clear();

        BufferedReader exerciseReader = null;

        BufferedReader answerReader = null;

        Map<Integer, String> result = new HashMap<>();

        try {
            if (!exercisefile.exists()) {
                System.out.println("练习答案文件不存在");
                return null;
            }
            if (!answerFile.exists()) {
                System.out.println("答案文件不存在");
                return null;
            }
            if (!exercisefile.getName().matches(".+(.txt)$") || !answerFile.getName().matches(".+(.txt)$")) {
                System.out.println("文件格式不支持");
                return null;
            }

            InputStreamReader exerciseIn = new InputStreamReader(new FileInputStream(exercisefile.getAbsolutePath()), StandardCharsets.UTF_8);
            InputStreamReader answerIn = new InputStreamReader(new FileInputStream(answerFile.getAbsolutePath()), StandardCharsets.UTF_8);
            exerciseReader = new BufferedReader(exerciseIn);
            answerReader = new BufferedReader(answerIn);
            //将题号和答案对应存储,以防止出现漏写某一道题的情况
            Map<Integer, String> exerciseMap = new HashMap<>();
            Map<Integer, String> answerMap = new HashMap<>();
            String content = null;
            while ((content = exerciseReader.readLine()) != null) {
                //去除字符串的所有空格
                content = content.replaceAll(" +", "");
                content = content.replaceAll("uFEFF", "");
                if (!isQualified(content, false)) {
                    System.out.println(content);
                    System.out.println("文本的内容格式错误");
                    return null;
                }
                exerciseMap.put(Integer.valueOf(content.split("\.")[0]), content.split("\.")[1]);
            }
            while ((content = answerReader.readLine()) != null) {
                //去除字符串的所有空格
                content = content.replaceAll(" +", "");
                content = content.replaceAll("uFEFF", "");
                if (!isQualified(content, true)) {
                    System.out.println(content);
                    System.out.println("文本的内容格式错误");
                    return null;
                }
                answerMap.put(Integer.valueOf(content.split("\.")[0]), content.split("\.")[1]);
            }
            exerciseReader.close();
            answerReader.close();
            //比对结果
            for (int i = 1; i <= answerMap.size(); i++) {
                if (exerciseMap.containsKey(i)) {
                    //将答案切割出来(格式:3+2=5)
                    String exercise = exerciseMap.get(i).split("=")[1];

                    // 将答案写入图形化界面的表格
                    AnswerResult answerResult = new AnswerResult();
                    answerResult.setQuestion(exerciseMap.get(i).split("\=")[0]);
                    answerResult.setAnswerByStudent(exercise);
                    answerResult.setAnswerByProject(answerMap.get(i));
                    Controller.operationData.add(answerResult);

                    if (answerMap.get(i).equals(exercise)) {
                        //结果正确,将题号记录下来
                        result.put(i, "right");
                    } else {
                        result.put(i, "error");
                    }
                }
                //说明该题漏写或者错误
                else {
                    result.put(i, "error");
                }
            }

        } catch (IOException e) {
            System.out.println("读取文件错误");
        }
        return result;
    }

    //判断文本的内容是否符合要求
    private static Boolean isQualified(String content, Boolean isAnswer) {
        //如果是答案的格式
        if (isAnswer) {
            Matcher matcher = patten.matcher(content);
            if (!matcher.find()) {
                return false;
            }
            if (matcher.group().equals(content)) {
                //说明内容完全匹配
                return true;
            }
            return false;
        }
        else {
            //说明是表达式
            String matches = "[1-9][0-9]*\.[0-9,\',\/,\+,\-,\(,\),\×,\÷]+\=[0-9]+";
            if (content.matches(matches)) {
                return true;
            }
            return false;
        }
    }

    public static void main(String[] args) {
        String expression = "uFEFF1.(0÷2)×6=0";
        System.out.println(expression.matches("[1-9][0-9]*\.[0-9,\',\/,\+,\-,\(,\),\×,\÷]+\=[0-9]+"));
    }
}
复制代码

 六、测试运行

1、GUI生成题目: 如直接点击生成题目或参数输入错误,便会出现以上提示;

正确输入参数之后便会显示如下界面:

当点击生成题目按钮过于频繁时,则会出现以下提示:

2、 若是在控制台生成题目,同时会自动生成exercise.txt和answer.txt;若在图形界面,则只会自动生成answer.txt,用户可通过点击下载按钮来生成exercise.txt题目文件;

生成的文件如下:

 

 执行校对答案功能:若未选择文件,则会进行响应提示

 3、控制台结果显示:

GUI界面显示


七、PSP表格

PSP2.1

Personal Software Process Stages

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

 200

 210

· Estimate

· 估计这个任务需要多少时间

 200

 210

Development

开发

 450     

 490

· Analysis

· 需求分析 (包括学习新技术)

 60

 70

· Design Spec

· 生成设计文档

 55

 60

· Design Review

· 设计复审 (和同事审核设计文档)

 15

 10

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

 30

 35

· Design

· 具体设计

 50

 55

· Coding

· 具体编码

 180

 200

· Code Review

· 代码复审

 30

 30

· Test

· 测试(自我测试,修改代码,提交修改)

 30

 30

Reporting

报告

 50

 50 

· Test Report

· 测试报告

 20 

 20 

· Size Measurement

· 计算工作量

 10 

 10 

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

 20

 20

合计

 700

 750


八、项目小结

1、对业务处理有了更清晰的认识。

2、对于表达式的计算有了更深的理解。

3、对于文件的IO流更加熟悉。

4、同时对于正则表达式的使用更加熟悉。

5、对于结对编程,队友之间的配合有了进一步提升。

原文地址:https://www.cnblogs.com/huange7/p/12671480.html