import json import os import re from functools import lru_cache from django.conf import settings from judge.sql_runner import SQLCaseError, build_display from utils.shortcuts import natural_sort_key TEMPLATE_BASE = """//PREPEND BEGIN {} //PREPEND END //TEMPLATE BEGIN {} //TEMPLATE END //APPEND BEGIN {} //APPEND END""" @lru_cache(maxsize=100) def parse_problem_template(template_str): prepend = re.findall(r"//PREPEND BEGIN\n([\s\S]+?)//PREPEND END", template_str) template = re.findall(r"//TEMPLATE BEGIN\n([\s\S]+?)//TEMPLATE END", template_str) append = re.findall(r"//APPEND BEGIN\n([\s\S]+?)//APPEND END", template_str) return {"prepend": prepend[0] if prepend else "", "template": template[0] if template else "", "append": append[0] if append else ""} @lru_cache(maxsize=100) def build_problem_template(prepend, template, append): return TEMPLATE_BASE.format(prepend, template, append) def generate_sql_display(test_case_id, answers, sql_config): """SQL 题:用测试点1的初始化脚本 + 标准答案生成题目页展示数据。 返回 (sql_display, error):成功时 error 为 None,失败时 sql_display 为 None、error 为中文提示。 """ test_case_dir = os.path.join(settings.TEST_CASE_DIR, test_case_id) try: with open(os.path.join(test_case_dir, "info"), encoding="utf-8") as f: info = json.load(f) except (OSError, json.JSONDecodeError): return None, "测试点信息读取失败,请重新上传测试点" if not info.get("sql"): return None, "测试点不是 SQL 类型,请重新上传 SQL 测试点压缩包" try: keys = sorted(info["test_cases"].keys(), key=natural_sort_key) if not keys: return None, "题目没有任何测试点" input_name = info["test_cases"][keys[0]]["input_name"] except (KeyError, AttributeError, TypeError): return None, "测试点信息损坏,请重新上传测试点" try: with open(os.path.join(test_case_dir, input_name), encoding="utf-8") as f: init_sql = f.read() except OSError: return None, f"测试点脚本 {input_name} 读取失败" ref_sql = next((item["code"] for item in answers or [] if item.get("language") == "SQL" and item.get("code", "").strip()), None) if ref_sql is None: return None, "题目缺少 SQL 标准答案" try: return build_display(init_sql, ref_sql, sql_config["mode"]), None except SQLCaseError as e: return None, f"SQL 展示数据生成失败: {e.message}"