\frac{ $content = preg_replace('/\\\\([a-zA-Z]+)\s+\{/', '\\\\$1{', $content); // 4.2 移除花括号内的前导和尾随空格: { 1 } -> {1} $content = preg_replace('/\{\s+/', '{', $content); $content = preg_replace('/\s+\}/', '}', $content); // 4.3 移除上标/下标符号周围的空格: x ^ { a } -> x^{a} $content = preg_replace('/\s*\^\s*\{\s*/', '^{', $content); $content = preg_replace('/\s*_\s*\{\s*/', '_{', $content); // 4.4 移除 \left 和 \right 后的空格: \left ( -> \left( $content = preg_replace('/\\\\(left|right)\s+/', '\\\\$1', $content); // 4.5 移除括号内侧的空格: ( x ) -> (x) $content = preg_replace('/\(\s+/', '(', $content); $content = preg_replace('/\s+\)/', ')', $content); // 4.6 规范化多个连续空格为单个空格 $content = preg_replace('/\s+/', ' ', $content); // 4.7 清理 OCR 错误产生的多余 $ 符号 // 移除花括号内的 $: {a$} -> {a} $content = preg_replace('/\{([^}]*)\$+([^}]*)\}/', '{$1$2}', $content); // 移除末尾的多余 $$$ $content = preg_replace('/\$+\s*$/', '', $content); // 移除开头的多余 $$$ $content = preg_replace('/^\s*\$+/', '', $content); // 移除连续的 $$$ (3个或更多) $content = preg_replace('/\$\$\$+/', '$$', $content); // 5. 处理定界符 // 如果内容已经是完整的公式(被 $ 或 $$ 包裹),则保持原样 if (self::hasDelimiters($content)) { $content = self::cleanInsideDelimiters($content); return $content; } // 6. 智能包装 (统一处理混合内容) // 无论是纯文本还是富文本,都使用智能识别来包裹公式 // 这能同时处理: // - "已知函数 f(x) = ..." (未包裹的混合内容) // - "验证:$2x...$" (部分包裹的混合内容) // - "4x^2 - 25y^2" (未包裹的纯公式) // 先清理已有的定界符内部 $content = self::cleanInsideDelimiters($content); // 然后智能包裹剩余的数学部分 $content = self::smartWrapMixedContent($content); return $content; } /** * 清理定界符内部的 HTML 标签 */ private static function cleanInsideDelimiters(string $content): string { // 修复:使用更精确的正则表达式,避免模式冲突 // 先处理 $$...$$ 模式,然后处理单个 $...$ 模式(但确保不被$$包含) // 1. 处理 $$...$$ 显示公式 $content = preg_replace_callback('/\$\$([\s\S]*?)\$\$/', function ($matches) { $cleanContent = strip_tags($matches[1]); $cleanContent = html_entity_decode($cleanContent, ENT_QUOTES, 'UTF-8'); $cleanContent = trim($cleanContent); return '$$' . $cleanContent . '$$'; }, $content); // 2. 处理 \(...\) 行内公式 $content = preg_replace_callback('/\\\\\(([\s\S]*?)\\\\\)/', function ($matches) { $cleanContent = strip_tags($matches[1]); $cleanContent = html_entity_decode($cleanContent, ENT_QUOTES, 'UTF-8'); $cleanContent = trim($cleanContent); return '\\(' . $cleanContent . '\\)'; }, $content); // 3. 处理 \[...\] 显示公式 $content = preg_replace_callback('/\\\\\[([\s\S]*?)\\\\\]/', function ($matches) { $cleanContent = strip_tags($matches[1]); $cleanContent = html_entity_decode($cleanContent, ENT_QUOTES, 'UTF-8'); $cleanContent = trim($cleanContent); return '\\[' . $cleanContent . '\\]'; }, $content); // 4. 最后处理 $...$ 行内公式(避免与$$冲突) $content = preg_replace_callback('/(?]+>'; // 匹配已有的定界符 $existingDelimiterPattern = '(?:\$\$[\s\S]*?\$\$|\$[\s\S]*?\$|\\\\\([\s\S]*?\\\\\)|\\\\\[[\s\S]*?\\\\\])'; // 数学公式特征: // 1. 函数定义: f(x) = ... // 2. 等式/不等式: ... = ..., ... > ..., ... < ... // 3. 包含 LaTeX 命令: \sqrt, \frac 等 // 4. 包含上标/下标: x^2, a_n // 匹配函数定义或等式 (例如 f(x) = 2x^2 + 1) // 必须包含 = 或 > 或 <,且周围有类数学字符 $equationPattern = '(?]\s*[\w\s\+\-\*\/\^\.\(\)\{\}\\\\]+(?=\s|$|<|[.,;])'; // 匹配显式 LaTeX 命令 (例如 \sqrt{...}) $latexPattern = '\\\\[a-zA-Z]+(?:\{[^\}]*\})?'; // 匹配简单的代数项 (例如 x^2, a_n) - 需谨慎,避免匹配普通单词 $algebraPattern = '(?', '^', '_', '{', '}']; foreach ($symbols as $symbol) { if (strpos($content, $symbol) !== false) { // 排除普通文本中的符号(如连字符),这里做一个简单的宽容判断 // 如果有数字紧随其后,或者是特定组合 return true; } } // 3. 检查数字和字母的组合 (如 2x, x^2) if (preg_match('/[a-zA-Z]\d|\d[a-zA-Z]/', $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; } }