/** * 数学公式预处理器 * 用于标准化各种数学公式格式,避免渲染死循环 */ window.MathFormulaProcessor = { /** * 预处理数学公式内容 * @param {string} content 原始内容 * @return {string} 处理后的内容 */ processContent: function(content) { if (!content || typeof content !== 'string') { return content; } // 0. 先清理重复分隔符(如 $$$ -> $$),该步始终执行 content = this.cleanupDuplicateMarkers(content); if (!this.shouldPreprocess(content)) { return content; } // 1. 标准化数学公式分隔符 content = this.standardizeDelimiters(content); // 1.5 清理重复分隔符(如 $$$ -> $ 或 $$) content = this.cleanupDuplicateMarkers(content); // 2. 转义特殊字符 content = this.escapeSpecialChars(content); // 3. 修复常见的LaTeX错误 content = this.fixLatexErrors(content); return content; }, /** * 是否需要预处理(平衡的 $…$ 且无占位词时跳过,避免过度修改) */ shouldPreprocess: function(content) { // 已有占位/异常字符则需要处理 if (content.includes('\\text{空') || content.includes('题目内容')) { return true; } // 连续三个及以上 $ 需要清理 if (/\${3,}/.test(content)) { return true; } // 统计 $ 个数,偶数且>0 时视为平衡 const dollarCount = (content.match(/\$/g) || []).length; if (dollarCount > 0 && dollarCount % 2 === 0) { return false; } // 含有 \(\ 或 \[\ 等特殊定界符时仍可处理 if (content.includes('\\(') || content.includes('\\[')) { return true; } return true; }, /** * 标准化数学公式分隔符 */ standardizeDelimiters: function(content) { // 统一使用 $ 和 $$ 作为分隔符 content = content.replace(/\\\(\\s*\$/g, '$'); content = content.replace(/\$\\s*\\\)/g, '$'); content = content.replace(/\\\[\\s*\$/g, '$$'); content = content.replace(/\$\\s*\\\]/g, '$$'); return content; }, /** * 转义特殊字符,防止渲染冲突 */ escapeSpecialChars: function(content) { // 检测是否已经在公式中 let inFormula = false; let result = ''; for (let i = 0; i < content.length; i++) { const char = content[i]; const nextChar = content[i + 1]; // 检测公式开始 if (char === '$' && nextChar === '$') { inFormula = true; result += char; i++; // 跳过下一个$ continue; } if (char === '$') { inFormula = !inFormula; result += char; continue; } // 在公式外转义某些字符 if (!inFormula) { switch (char) { case '\\': // 只转义不是LaTeX命令的反斜杠 if (this.isLatexCommand(content, i)) { result += char; } else { result += '\\\\'; } break; case '{': case '}': result += char; break; default: result += char; } } else { result += char; } } return result; }, /** * 检测当前位置是否在LaTeX命令中 */ isLatexCommand: function(content, index) { // 简单检测:查看反斜杠后面是否跟着字母 let i = index + 1; while (i < content.length && /\s/.test(content[i])) { i++; } return i < content.length && /[a-zA-Z]/.test(content[i]); }, /** * 修复常见的LaTeX错误 */ fixLatexErrors: function(content) { // 1. 修复不匹配的公式分隔符 let formulaCount = 0; let inDisplayFormula = false; for (let i = 0; i < content.length; i++) { if (content[i] === '$' && content[i + 1] === '$') { if (inDisplayFormula) { formulaCount++; inDisplayFormula = false; } else { inDisplayFormula = true; } i++; // 跳过下一个$ } else if (content[i] === '$') { formulaCount++; } } // 如果公式数量是奇数,补全分隔符 if (formulaCount % 2 === 1) { content += '$'; } // 2. 清理空的数学公式(不再插入“空”占位,直接移除) content = content.replace(/\$\s*\$/g, ' '); content = content.replace(/\$\$\s*\$\$/g, ' '); return content; }, /** * 清理重复的数学公式标记 */ cleanupDuplicateMarkers: function(content) { // 移除连续的相同分隔符 content = content.replace(/\$\$\$\$\$/g, '$$'); content = content.replace(/\$\$\$/g, '$'); // 处理起始为 "$$...$" 的不匹配情况,改为单行公式 "$...$" content = content.replace(/^\$\$(.+)\$/s, (_, inner) => `$${inner}$`); return content; } };