From b7607d3c9ce97335c8df85d1403dcddeda5f5370 Mon Sep 17 00:00:00 2001 From: dlaren Date: Tue, 22 Jul 2025 15:01:36 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E4=BF=AE=E6=94=B9=E3=80=91C=E8=AF=AD?= =?UTF-8?q?=E8=A8=80=E6=9C=AC=E5=9C=B0=E5=88=A4=E5=88=86=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B=EF=BC=8C=E5=85=B3?= =?UTF-8?q?=E9=94=AE=E5=AD=97=E6=AF=94=E5=AF=B9=EF=BC=8C=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=AE=B5=E8=AF=BB=E5=8F=96=EF=BC=8C=E7=BB=93=E6=9E=9C=E6=91=98?= =?UTF-8?q?=E8=A6=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exam/service/c/JudgementServiceImpl.java | 181 +++++++++++++----- 1 file changed, 138 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/example/exam/exam/service/c/JudgementServiceImpl.java b/src/main/java/com/example/exam/exam/service/c/JudgementServiceImpl.java index 63ce131..a6c9a9c 100644 --- a/src/main/java/com/example/exam/exam/service/c/JudgementServiceImpl.java +++ b/src/main/java/com/example/exam/exam/service/c/JudgementServiceImpl.java @@ -10,7 +10,10 @@ import org.springframework.stereotype.Service; import com.example.exam.exam.dal.SourceAndText; import java.io.IOException; +import java.math.BigDecimal; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * 判分逻辑集合 @@ -66,17 +69,12 @@ public class JudgementServiceImpl implements JudgementService double pass_score = score * is_pass_score; // 创建log文件txt,用于记录 -// LogFileUtils.createFile(pathC + "/log.txt"); System.out.println(pathC + " --- " + fileName); String code = JudgementCUtils.readFile(pathC, fileName); -// LogFileUtils.writeLine("✅ 系统开始读取学生考试文件:" + code); judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 系统开始读取学生考试文件:" + code); if (code == "") { // 如果没有读到源码 -// LogFileUtils.writeLine("❌ 系统没有读取到学生考试文件。"); judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "❌ 系统没有读取到学生考试文件。"); - -// LogFileUtils.close(); // 该题不得分,直接算成0分 sourceAndText.setScore(0); sourceAndText.setText(judgementStr); @@ -88,17 +86,27 @@ public class JudgementServiceImpl implements JudgementService // 总权重值 int weight = 0; List> key_list = new ArrayList<>(); - // 进行关键字权重比对进行判断 + // 只获取 /\\*+Program\\*+/(.*?)/\\*+ End \\*+/ 下的代码进行判断 + String pattern = "/\\*+Program\\*+/(.*?)/\\*+ End \\*+/"; + Pattern r = Pattern.compile(pattern, Pattern.DOTALL); + Matcher m = r.matcher(code); + String result; + if (m.find()) { + result = m.group(1).trim(); // 提取代码段 + } else { + result = code; // 如果没有匹配到标识符,返回全部代码 + } + + // 进行关键字权重比对进行判断 for (ExamQuestionKeyword examQuestionKeyword : examQuestion.getQuestionKeywords()) { - String codeSpacking = code.replace(" ",""); + String codeSpacking = result.replace(" ",""); boolean keyword_run = codeSpacking.contains(examQuestionKeyword.getKeyword()); // 计算权值 Map item = new HashMap<>(); item.put("success", keyword_run); item.put("score_rate", examQuestionKeyword.getScoreRate()); -// LogFileUtils.writeLine("✅ 关键字比对:" + examQuestionKeyword.getKeyword() + "--" + (keyword_run ? "正确" : "错误")); - judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 关键字比对:" + examQuestionKeyword.getKeyword() + " -- " + (keyword_run ? "正确" : "错误")); + item.put("text", examQuestionKeyword.getKeyword()); weight += Integer.parseInt(examQuestionKeyword.getScoreRate()); key_list.add(item); } @@ -112,8 +120,10 @@ public class JudgementServiceImpl implements JudgementService // 每个选项分值 = 总分 / 总权重 true_number += 1; key_score += one_keyword_score * Integer.parseInt((String) item.get("score_rate")); -// LogFileUtils.writeLine("✅ 关键字得分:" + key_score); - judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 关键字得分:" + key_score); + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 关键字比对:" + item.get("text") + " -- 正确 -- 得分:" + one_keyword_score * Integer.parseInt((String) item.get("score_rate"))); + } else { + // 关键字不正确 + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "❌ 关键字比对:" + item.get("text") + " -- 错误 -- 得分:0"); } } @@ -126,34 +136,110 @@ public class JudgementServiceImpl implements JudgementService // 测试用例(比编译通过提前) // 判断是否要程序结果 ,需要程序结果的,就需要测试用例 if (is_compile) { + // 测试用例数组,记录测试用的正确错误情况 + List> compileList = new ArrayList<>(); // 先运行程序,再将测试用例进行比对 // 运行完成后在判断是否需要进行关键字比对 boolean run_code = false; - List runList = new ArrayList<>(); -// LogFileUtils.writeLine("✅ 使用c99标准进行测试用例编译..."); judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 使用c99标准进行测试用例编译..."); boolean isPassIndex = false; for (ExamQuestionAnswer examQuestionAnswer : examQuestion.getAnswerList()) { + Map item = new HashMap<>(); + // 使用C99 运行并得出结果 String code_return = JudgementCUtils.run_code(pathC,code, examQuestionAnswer.getContentIn(),"-std=c99",null); if (!isPassIndex && !code_return.contains("error")) { // 编译没有报错,加上编译分数 totalScore += pass_score; -// LogFileUtils.writeLine("✅ 编译通过得分:" + pass_score); isPassIndex = true; judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 编译通过得分:" + pass_score); } else if (!isPassIndex) { -// LogFileUtils.writeLine("❌ 编译未通过。"); + isPassIndex = true; + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "❌ 编译未通过。"); + } + + String actual = extractUnwrappedText(code_return).trim(); + String expected = examQuestionAnswer.getContent().trim(); + // 分值权重 + item.put("scoreRate", examQuestionAnswer.getScoreRate()); + item.put("inText", examQuestionAnswer.getContentIn()); + item.put("resultText", actual); + item.put("resultTrueText", expected); + if (actual.equals(expected)) { + item.put("success", true); + // 获取测试用例临界值,并进行判断 +// if (runList.size() >= Integer.parseInt(examQuestion.getQuestionScores().getCompileCutoff()) && !runList.contains(false)) { +// // 测试用例得分 +// compile_score += (double) (score * is_compile_score); +// // 结果得分 +// result_score += (double) (score * is_result_score); +// LogFileUtils.writeLine("✅ 测试用例得分:" + compile_score); +// break; +// } + } else { + item.put("success", false); + } + compileList.add(item); + } + // 记录存在多少个测试用例,并且同时记录正确测试用例个数 + int test_case_number = compileList.size(); + // 测试用例进行分开使用 + // 测试用例分数站总分的值 + BigDecimal compileScore = new BigDecimal(score * is_compile_score); + for (Map item : compileList) { + boolean success = (boolean) item.get("success"); + String scoreRate = (String) item.get("scoreRate"); + String inText = (String) item.get("inText"); + String resultText = (String) item.get("resultText"); + String resultTrueText = (String) item.get("resultTrueText"); + + // 单个测试用例的分值权重 + BigDecimal singleScore = new BigDecimal((double) Integer.parseInt(scoreRate) / 100).setScale(2, BigDecimal.ROUND_HALF_UP); + // 单个测试用例正确情况下得分 + BigDecimal oneCompileScore = compileScore.multiply(singleScore).setScale(2, BigDecimal.ROUND_HALF_UP); + compile_score += Double.parseDouble(oneCompileScore.toString()); + if (success) { + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 测试用例:输入("+ + inText + ")" + + ",正确结果:(" + resultTrueText + ")" + + ",学生结果:(" + resultText + ")" + + ",正确,得分:" + Double.parseDouble(oneCompileScore.toString())); + } else { + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "❌ 测试用例:输入("+ + inText + ")" + + ",正确结果:(" + resultTrueText + ")" + + ",学生结果:(" + resultText + ")" + + ",错误,得分:0"); + } + + + } + } else if (is_result) { + // 编译代码运行,无测试用例,直接代码运行结果比对 + boolean run_code = false; + List runList = new ArrayList<>(); + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 使用c99标准进行结果编译..."); + boolean isPassIndex = false; + for (ExamQuestionAnswer examQuestionAnswer : examQuestion.getAnswerList()) { + // 使用C99 运行并得出结果 + String code_return = JudgementCUtils.run_code(pathC,code, null,"-std=c99",null); + if (!isPassIndex && !code_return.contains("error")) { + // 编译没有报错,加上编译分数 + totalScore += pass_score; + isPassIndex = true; + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 编译通过得分:" + pass_score); + + } else if (!isPassIndex) { isPassIndex = true; judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "❌ 编译未通过。"); } String actual = code_return.trim(); String expected = examQuestionAnswer.getContent().trim(); if (actual.equals(expected)) { - // 判断测试用例结果是否正确 - runList.add(true); - // 获取测试用例临界值,并进行判断 + // 判断结果是否正确 + runList.add(true); + // 获取结果临界值,并进行判断 // if (runList.size() >= Integer.parseInt(examQuestion.getQuestionScores().getCompileCutoff()) && !runList.contains(false)) { // // 测试用例得分 // compile_score += (double) (score * is_compile_score); @@ -164,32 +250,27 @@ public class JudgementServiceImpl implements JudgementService // } } } - // 记录存在多少个测试用例,并且同时记录正确测试用例个数 + // 记录存在多少个结果,并且同时记录正确结果个数 int test_case_number = examQuestion.getAnswerList().size(); int true_test_case_number = runList.size(); - // 判断正确关系 // 1、如果完全相等,说明完全正确,直接给满分 if (test_case_number == true_test_case_number) { // 满分,该题多少分就是多少分 -// LogFileUtils.writeLine("✅ 测试用例全部正确:"+ score); - judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 测试用例全部正确:"+ score); -// LogFileUtils.close(); + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 结果全部正确:"+ score); sourceAndText.setScore(score); sourceAndText.setText(judgementStr); return sourceAndText; } else if (test_case_number > true_test_case_number) { - // 2、测试用例没有完全正确,对多少个就是多少分 - // 公式:测试用例总分数 / 测试用例数量 * 正确测试用例数量 + // 2、结果没有完全正确,对多少个就是多少分 + // 公式:结果总分数 / 结果数量 * 正确结果数量 compile_score += (double) ((score * is_compile_score) / test_case_number) * true_test_case_number; -// LogFileUtils.writeLine("✅ 测试用例数量:"+ test_case_number + ",正确数量:" + true_test_case_number + ",得分:" + compile_score); - judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 测试用例数量:"+ test_case_number + ",正确数量:" + true_test_case_number + ",得分:" + compile_score); + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 结果数量:"+ test_case_number + ",正确数量:" + true_test_case_number + ",得分:" + compile_score); } } else if (is_pass) { // 编译代码运行 // 如果使用程序编译,进行程序编译 -// LogFileUtils.writeLine("✅ 使用c99标准进行编译..."); judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 使用c99标准进行编译..."); // 使用C99 运行并得出结果 @@ -197,40 +278,54 @@ public class JudgementServiceImpl implements JudgementService if (!code_return.contains("error")) { // 编译没有报错,加上编译分数 totalScore += pass_score; -// LogFileUtils.writeLine("✅ 编译通过得分:" + pass_score); judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 编译通过得分:" + pass_score); } else { -// LogFileUtils.writeLine("❌ 编译未通过。"); judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "❌ 编译未通过。"); } } // 总分 = 总分 + 测试用例得分 totalScore += compile_score; - if (compile_score > 0) { - // 如果测试用例正确有得分的 - // 结果 - if (is_result) { - // 总分 = 总分 + 结果得分 - totalScore += result_score; -// LogFileUtils.writeLine("✅ 结果得分:" + result_score); - judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 结果得分:" + result_score); - } - } +// if (compile_score > 0) { +// // 如果测试用例正确有得分的 +// // 结果 +// if (is_result) { +// // 总分 = 总分 + 结果得分 +// totalScore += result_score; +//// LogFileUtils.writeLine("✅ 结果得分:" + result_score); +// judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 结果得分:" + result_score); +// } +// } totalScore += key_score; -// LogFileUtils.close(); sourceAndText.setScore(totalScore); sourceAndText.setText(judgementStr); return sourceAndText; } else { // 关键字对几个给几分,没有达到临界值的情况下 totalScore += key_score; -// LogFileUtils.writeLine("❌ 关键字没有达到临界值,正确数量:"+ true_number); judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "❌ 关键字没有达到临界值,正确数量:"+ true_number); -// LogFileUtils.close(); sourceAndText.setScore(totalScore); sourceAndText.setText(judgementStr); return sourceAndText; } } + public static String extractUnwrappedText(String input) { + // 检查 【 和 】 是否成对出现 + int openBrackets = countOccurrences(input, "【"); + int closeBrackets = countOccurrences(input, "】"); + + if (openBrackets != closeBrackets) { + return input; // 不成对,直接返回原字符串 + } else if (openBrackets == 0) { + return input; // 没有【】,直接返回原字符串 + } else { + // 成对,移除所有【.*?】 + return input.replaceAll("【.*?】", ""); + } + } + + // 统计字符串中某个子串的出现次数 + private static int countOccurrences(String str, String subStr) { + return str.split(subStr, -1).length - 1; + } }