大侠咬超人 2 days ago
parent
commit
35876c1424
1 changed files with 44 additions and 8 deletions
  1. 44 8
      scripts/katex-render.mjs

+ 44 - 8
scripts/katex-render.mjs

@@ -57,6 +57,29 @@ process.stdin.on('end', () => {
     }
 });
 
+/**
+ * 解码 HTML 实体
+ */
+function decodeHtmlEntities(text) {
+    return text
+        .replace(/&lt;/g, '<')
+        .replace(/&gt;/g, '>')
+        .replace(/&amp;/g, '&')
+        .replace(/&quot;/g, '"')
+        .replace(/&#39;/g, "'")
+        .replace(/&nbsp;/g, ' ');
+}
+
+/**
+ * 编码 HTML 实体(用于安全输出)
+ */
+function encodeHtmlEntities(text) {
+    return text
+        .replace(/&/g, '&amp;')
+        .replace(/</g, '&lt;')
+        .replace(/>/g, '&gt;');
+}
+
 /**
  * 渲染 HTML 中的所有数学公式
  */
@@ -90,38 +113,51 @@ function processDelimiter(html, left, right, displayMode) {
     const rightEscaped = escapeRegex(right);
 
     // 构建正则表达式
-    // 对于 $ ... $,需要确保不匹配 $$ ... $$
+    // 【关键修复】排除包含 HTML 标签的内容(不匹配 < 或 >)
     let pattern;
     if (left === '$' && right === '$') {
-        // 单个 $ 不能紧跟另一个 $
-        pattern = new RegExp(`(?<!\\$)\\$(?!\\$)([^$]+?)(?<!\\$)\\$(?!\\$)`, 'g');
+        // 单个 $...$:不匹配 $$,不匹配包含 < > 的内容
+        pattern = new RegExp(`(?<!\\$)\\$(?!\\$)([^$<>]+?)(?<!\\$)\\$(?!\\$)`, 'g');
+    } else if (left === '$$' && right === '$$') {
+        // $$...$$:不匹配包含 < > 的内容
+        pattern = new RegExp(`\\$\\$([^<>]*?)\\$\\$`, 'g');
     } else {
-        pattern = new RegExp(`${leftEscaped}([\\s\\S]*?)${rightEscaped}`, 'g');
+        // \(...\) 和 \[...\]:不匹配包含 < > 的内容
+        pattern = new RegExp(`${leftEscaped}([^<>]*?)${rightEscaped}`, 'g');
     }
 
     return html.replace(pattern, (match, latex) => {
         try {
-            // 清理 LaTeX 内容
-            let cleanLatex = latex.trim();
+            // 清理 LaTeX 内容 - 先解码 HTML 实体
+            let cleanLatex = decodeHtmlEntities(latex.trim());
 
             // 跳过空内容
             if (!cleanLatex) {
                 return match;
             }
 
+            // 【安全检查】如果内容看起来不像 LaTeX,跳过
+            // 跳过只有普通文本的内容(没有任何 LaTeX 特征)
+            if (!/[\\^_{}]/.test(cleanLatex) && !/[a-zA-Z]{2,}/.test(cleanLatex)) {
+                // 可能只是普通数字或单字母,检查是否有意义
+                if (/^[\d\s\.\,\-\+]+$/.test(cleanLatex)) {
+                    return match; // 纯数字,不渲染
+                }
+            }
+
             // 渲染 KaTeX
             const rendered = katex.renderToString(cleanLatex, {
                 displayMode: displayMode,
                 throwOnError: false,
                 strict: false,
                 trust: true,
-                output: 'html', // 使用 HTML 输出(比 mathml 兼容性更好)
+                output: 'html',
             });
 
             return rendered;
         } catch (error) {
             // 渲染失败时保留原始内容
-            console.error(`KaTeX error for "${latex.substring(0, 50)}...":`, error.message);
+            // console.error(`KaTeX error for "${latex.substring(0, 50)}...":`, error.message);
             return match;
         }
     });