Forráskód Böngészése

fix: 继续修复判卷里解题思路里的公式显示问题

过卫栋 2 napja
szülő
commit
1528b800fd

+ 4 - 2
app/Services/ExamPdfExportService.php

@@ -2124,8 +2124,10 @@ class ExamPdfExportService
         if ($text === null) {
             return null;
         }
-        // 替换 \n 为 <br>,然后合并连续的 <br>(最多保留2个)
-        $text = str_replace('\\n', '<br>', $text);
+        // 【修复】替换 \n 为 <br>,但保护 LaTeX 命令如 \neq, \ne, \newline, \nu 等
+        // 使用负向前瞻 (?![a-zA-Z]) 避免误伤 LaTeX 命令
+        $text = preg_replace('/\\\\n(?![a-zA-Z])/', '<br>', $text);
+        // 合并连续的 <br>(最多保留2个)
         return preg_replace('/(<br>\s*){3,}/', '<br><br>', $text);
     }
 

+ 51 - 5
app/Services/MathFormulaProcessor.php

@@ -26,15 +26,19 @@ class MathFormulaProcessor
         }
         $content = trim($content);
 
-        // 1. 如果已有正确的定界符,只清理内部 HTML,不做其他修改
-        if (self::hasDelimiters($content)) {
-            return self::cleanInsideDelimiters($content);
+        // 1. 【关键修复】处理公式内的双反斜杠 -> 单反斜杠
+        // 数据库存储时 \sqrt 变成 \\sqrt,需要还原
+        $content = self::normalizeBackslashesInDelimiters($content);
+
+        // 2. 如果内容中包含定界符,清理内部 HTML
+        if (self::containsDelimiters($content)) {
+            $content = self::cleanInsideDelimiters($content);
         }
 
-        // 2. 检测内容类型:纯数学、混合内容还是纯文本
+        // 3. 检测内容类型:纯数学、混合内容还是纯文本
         $contentType = self::detectContentType($content);
 
-        // 3. 根据内容类型采取不同的处理策略
+        // 4. 根据内容类型采取不同的处理策略
         switch ($contentType) {
             case 'pure_math':
                 // 纯数学表达式,如 "4x^2 - 25y^2" 或 "f(x) = x^2 - 4x + 5"
@@ -51,6 +55,48 @@ class MathFormulaProcessor
         }
     }
 
+    /**
+     * 【新增】将公式定界符内的双反斜杠转为单反斜杠
+     * 与前端 MathText.tsx 的 preprocessText 逻辑保持一致
+     */
+    private static function normalizeBackslashesInDelimiters(string $content): string
+    {
+        // 1. 处理 $$...$$ 块级公式内的双反斜杠
+        $content = preg_replace_callback('/\$\$([\s\S]*?)\$\$/', function ($matches) {
+            $tex = str_replace('\\\\', '\\', $matches[1]);
+            return '$$' . $tex . '$$';
+        }, $content);
+
+        // 2. 处理 $...$ 行内公式内的双反斜杠(避免与$$冲突)
+        $content = preg_replace_callback('/(?<!\$)\$([^$\n]+?)\$(?!\$)/', function ($matches) {
+            $tex = str_replace('\\\\', '\\', $matches[1]);
+            return '$' . $tex . '$';
+        }, $content);
+
+        // 3. 处理 \(...\) 行内公式
+        $content = preg_replace_callback('/\\\\\(([\s\S]*?)\\\\\)/', function ($matches) {
+            $tex = str_replace('\\\\', '\\', $matches[1]);
+            return '\\(' . $tex . '\\)';
+        }, $content);
+
+        // 4. 处理 \[...\] 块级公式
+        $content = preg_replace_callback('/\\\\\[([\s\S]*?)\\\\\]/', function ($matches) {
+            $tex = str_replace('\\\\', '\\', $matches[1]);
+            return '\\[' . $tex . '\\]';
+        }, $content);
+
+        return $content;
+    }
+
+    /**
+     * 【新增】检查内容中是否包含任意定界符(不要求整个字符串被包裹)
+     */
+    private static function containsDelimiters(string $content): bool
+    {
+        // 检查是否包含 $...$, $$...$$, \(...\), \[...\]
+        return preg_match('/\$\$[\s\S]*?\$\$|\$[^$\n]+?\$|\\\\\([\s\S]*?\\\\\)|\\\\\[[\s\S]*?\\\\\]/', $content) === 1;
+    }
+
     /**
      * 检测内容类型
      * 优化:加入中文检测,避免包裹包含中文的混合内容