| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- /**
- * 数学公式预处理器
- * 用于标准化各种数学公式格式,避免渲染死循环
- */
- 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;
- }
- };
|