zoukankan      html  css  js  c++  java
  • 结对项目(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、对于结对编程,队友之间的配合有了进一步提升。

  • 相关阅读:
    el表达式调用函数
    EL表达式
    mapReducer程序编写过程
    hadoop2.Xeclipse插件编译
    hadoop搭建与eclipse开发环境设置
    Sqoop-1.4.4工具import和export使用详解
    ZooKeeper典型应用场景一览
    hive原理和体系图解
    Linux中ssh免秘钥设置
    Annotation版本的HelloWorld
  • 原文地址:https://www.cnblogs.com/huange7/p/12671480.html
Copyright © 2011-2022 走看看