]+>'; $existingDelimiterPattern = '(?:\$\$[\s\S]*?\$\$|\$[\s\S]*?\$|\\\\\([\s\S]*?\\\\\)|\\\\\[[\s\S]*?\\\\\])'; // 数学公式模式(按优先级排列) $patterns = [ // 1. 函数定义: f(x) = 2x^3 - 3x^2 + 4x - 5 "[a-zA-Z]'?\\([a-zA-Z0-9,\\s]+\\)\\s*=\\s*[a-zA-Z0-9\\+\\-\\*\\/\\^\\s\\.\\(\\)\\_\\{\\}]+", // 2. 导数/函数调用: f'(1), g(5), sin(x) "[a-zA-Z]+'?\\([a-zA-Z0-9\\+\\-\\*\\/\\^\\s\\.]+\\)", // 3. LaTeX 命令: \frac{1}{2} "\\\\[a-zA-Z]+\\{[^}]*\\}(?:\\{[^}]*\\})?", // 4. 数学表达式: x^2 + y^2, 2x - 3 "[a-zA-Z0-9]+[\\^_][a-zA-Z0-9\\{\\}]+(?:\\s*[\\+\\-\\*\\/]\\s*[a-zA-Z0-9\\^_\\{\\}\\.]+)*", ]; $mathPattern = '(?:' . implode('|', $patterns) . ')'; $pattern = "/($tagPattern)|($existingDelimiterPattern)|($mathPattern)/u"; return preg_replace_callback($pattern, function ($matches) { // HTML 标签,原样返回 if (!empty($matches[1])) { return $matches[1]; } // 已有的定界符,原样返回 if (!empty($matches[2])) { return $matches[2]; } // 数学公式,添加 $ 包裹 if (!empty($matches[3])) { $math = trim($matches[3]); // 再次检查是否已经包裹 if (str_contains($math, '$')) { return $math; } return '$' . $math . '$'; } return $matches[0]; }, $content); } /** * 检查是否已有定界符 */ private static function hasDelimiters(string $content): bool { $content = trim($content); // 检查 $$...$$ if (str_starts_with($content, '$$') && str_ends_with($content, '$$')) { return true; } // 检查 $...$ if (str_starts_with($content, '$') && str_ends_with($content, '$')) { return true; } // 检查 \[...\] if (str_starts_with($content, '\\[') && str_ends_with($content, '\\]')) { return true; } // 检查 \(...\) if (str_starts_with($content, '\\(') && str_ends_with($content, '\\)')) { return true; } return false; } /** * 检测数学特征 * 优化:更精确的检测,减少误判 */ private static function containsMathFeatures(string $content): bool { // 1. 检查是否有 LaTeX 命令 if (preg_match('/\\\\[a-zA-Z]+\{?/', $content)) { return true; } // 2. 检查函数定义或等式(如 f(x) =, g(x) =) // 必须是:字母+括号+等号+数学内容 if (preg_match('/[a-zA-Z]\([a-zA-Z0-9,\s]+\)\s*=\s*[a-zA-Z0-9\+\-\*\/\^\.\(\)\s\\\\_\{]+/', $content)) { return true; } // 3. 检查纯数学表达式(只包含数字、变量、运算符、括号) // 严格的数学表达式:必须包含字母和运算符,且没有中文字符 if (preg_match('/^[a-zA-Z0-9\+\-\*\/\=\s\.\^\(\)\_\{\}]+$/', $content) && preg_match('/[a-zA-Z]/', $content) && preg_match('/[\+\-\*\/\=\^]/', $content)) { return true; } // 4. 检查包含变量的数学表达式(带约束) // 必须有明确的运算符连接,且周围是数学内容 if (preg_match('/[a-zA-Z0-9\.\^\_\{\}]\s*[\+\-\*\/]\s*[a-zA-Z0-9\.\^\_\{\}\(\)]/', $content)) { return true; } // 5. 检查分数形式(如 \frac{}{}) if (preg_match('/\\\\frac\{/', $content)) { return true; } // 6. 检查上标或下标(仅当与数字/字母组合时) if (preg_match('/[a-zA-Z0-9]\s*[\^_]\s*[a-zA-Z0-9]/', $content)) { return true; } return false; } /** * 批量处理 */ public static function processArray(array $data, array $fieldsToProcess): array { foreach ($data as $key => &$value) { if (in_array($key, $fieldsToProcess) && is_string($value)) { $value = self::processFormulas($value); } elseif (is_array($value)) { $value = self::processArray($value, $fieldsToProcess); } } return $data; } /** * 处理题目数据 */ public static function processQuestionData(array $question): array { $fieldsToProcess = [ 'stem', 'content', 'question_text', 'answer', 'correct_answer', 'student_answer', 'explanation', 'solution', 'question_content' ]; return self::processArray($question, $fieldsToProcess); } /** * 修复被污染的数学公式(包含重复的转义字符) */ private static function fixCorruptedFormulas(string $content): string { // 简化的修复策略,只处理明确的问题 // 1. 将超过2个连续的$符号减少为2个 $content = preg_replace('/\${3,}/', '$$', $content); // 2. 修复$$B . - \frac{1}{2}$$ 这种格式,在选项前加空格 $content = preg_replace('/\$\$([A-Z])\s*\.\s*/', '$$ $1. ', $content); // 3. 修复不完整的frac命令:\frac{1}{2} -> \frac{1}{2} $content = preg_replace('/\\\\frac\\\\({[^}]+)([^}]*)\\\\/', '\\\\frac$1}{$2}', $content); // 4. 移除孤立的反斜杠(在非LaTeX命令前的) $content = preg_replace('/\\\\(?![a-zA-Z{])/', '', $content); return $content; } }