Автоматическое преобразование введенных математических данных в Latex/MathjaxJavascript

Форум по Javascript
Ответить
Anonymous
 Автоматическое преобразование введенных математических данных в Latex/Mathjax

Сообщение Anonymous »



Я использую систему управления обучением, взятую из моих коучинговых занятий, и из-за материалов, защищенных авторским правом, я не могу публиковать здесь скриншоты. Однако я везде пытаюсь преобразовать типизированную математику в математику Latex/Mathjax, чтобы ее было легче читать.
В основном что-то от 4X2=x2-2x до $4 \times 2 = x^2 - 2x$ и т. д.
Я пробовал программировать с Клодом, потому что у меня не было времени изучать JS самому (хотя, если бы я это сделал, код был бы намного лучше), и вот как далеко я зашел в этом. Я использую Tampermonkey.

Код: Выделить всё

// ==UserScript==
// u/name         Smart Math Auto-Renderer
// u/namespace    http://tampermonkey.net/
// u/version      9.2
// u/description  Detect math by indicators and render with MathJax
// u/match        *://*/*
// u/grant        none
// ==/UserScript==

(function() {
'use strict';

// Add CSS to prevent wrapping in math
const style = document.createElement('style');
style.textContent = `
.MathJax, [class*="MJX"], mjx-container {
white-space: nowrap !important;
overflow-x: auto !important;
}
`;
document.head.appendChild(style);

window.MathJax = {
tex: {
inlineMath: [
['
displayMath: [
['
processEscapes: true,
processEnvironments: true
},
options: {
skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
},
startup: {
pageReady: () => {
return MathJax.startup.defaultPageReady().then(() => {
console.log('✓ MathJax loaded');
setTimeout(convertMath, 1000);
});
}
}
};

let script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js';
script.async = true;
document.head.appendChild(script);

const processedNodes = new WeakSet();

function hasMathIndicators(text) {
if (/^(Solution:|Select one:|The correct answer is:|Given that)/.test(text)) {
return false;
}

const indicators = [
/=/,
/\d+\s*[+\-*/×]\s*\d+/,
/\d+%/,
/\d+\/\d+/,
/[a-z]\s*[+\-*/×=]\s*\d+/i,
/\d+\s*[a-z]/i,
/\^/,
/:/,
/X/
];

return indicators.some(pattern => pattern.test(text));
}

function processMathPart(math) {
// Insert spaces before capitals (for camelCase splitting)
math = math.replace(/([a-z])([A-Z])/g, '$1 $2');

// Insert space between letter and number
math = math.replace(/([a-z])(\d)/gi, '$1 $2');

// Insert space between number and capital letter
math = math.replace(/(\d)([A-Z])/g, '$1 $2');

// Convert "of" to proper spacing when between % and variable
math = math.replace(/%\s*of\s*([a-z0-9])/gi, '% \\text{ of } $1');

// Convert ALL X to times FIRST (before other replacements)
math = math.replace(/X/g, '

// Convert lowercase x to times when between numbers
math = math.replace(/(\d)\s*x\s*(\d)/gi, '$1 \\times $2');

// Convert ALL / to fractions
math = math.replace(/(\d+)\/\(([^)]+)\)/g, '\\frac{$1}{$2}'); math = math.replace(/(\d+)\s*\/\s*(\d+)/g, '\\frac{$1}{$2}'); math = math.replace(/(\d+)\/([a-z])/gi, '\\frac{$1}{$2}');

// Convert : to fractions (ratios)
math = math.replace(/(\d+)\s*:\s*(\d+)/g, '\\frac{$1}{$2}');

// Convert × symbol
math = math.replace(/×/g, '

// Handle powers
math = math.replace(/([a-wyz])\^(\d+)/gi, '$1^{$2}'); math = math.replace(/([a-wyz])2(?=\s|[+\-=)\]]|$)/gi, '$1^2');

// Handle % symbol
math = math.replace(/(\d+)%/g, '$1\\%');

// Rs currency
math = math.replace(/Rs\.?\s*(\d+)/gi, '\\text{Rs}$1'); math = math.replace(/Rs\.?\s*([a-z])/gi, '\\text{Rs}$1');

// Units
math = math.replace(/(\d+)\s*g(?=\s|$)/gi, '$1\\text{ g}');  math = math.replace(/(\d+)\s*kg(?=\s|$)/gi, '$1\\text{ kg}'); math = math.replace(/\s+(apples|liters?|l|meters?)(?=\s|$|[,.])/gi, '\\text{ $1}');

// Clean up spacing
math = math.replace(/\s+/g, ' ').trim();

return math;
}

function convertToLatex(text) {
// Don't process pure descriptive text
if (/^[A-Z][a-z\s,.']+$/i.test(text) && !/\d/.test(text) && !text.includes('=')) {
return text;
}

return processMathPart(text);
}

function convertMath() {
console.log('🔍 Scanning...');

const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT, {
acceptNode: (node) => {
if (processedNodes.has(node)) return NodeFilter.FILTER_REJECT;
if (node.parentElement.closest('script, style, code, pre, .MathJax, [class*="MJX"]')) {
return NodeFilter.FILTER_REJECT;
}
return NodeFilter.FILTER_ACCEPT;
}
}
);

let node;
const replacements = [];

while (node = walker.nextNode()) {
let text = node.textContent.trim();

if (text.length < 3) continue;
if (processedNodes.has(node)) continue;

// Skip labels
if (/^(Solution:|Select one:|[a-d]\.|The correct answer is:|Correct|Incorrect|Mark|Flag|Question)/.test(text)) {
continue;
}

if (hasMathIndicators(text)) {
const lines = text.split('\n');
const processedLines = lines.map(line => {
line = line.trim();

if (line.length < 3) return line;
if (line.startsWith('$')) return line;

// Skip answer options
if (/^[a-d]\.\s+/.test(line)) return line;

// Skip pure text sentences
if (/^[A-Z][a-z\s,.']+[^=\d]$/.test(line)) return line;

if (hasMathIndicators(line)) {
const latex = convertToLatex(line);

// Display math for equations with =
if (line.includes('=') && /\d/.test(line)) {
return `
} else if (/\d/.test(line)) {
return `
$$ {
latex
}
$`;
}
}
return line;
});

const newText = processedLines.join('\n');

if (newText !== text) {
replacements.push({node, newText});
processedNodes.add(node);
}
}
}

console.log(`📝
Found $ {
replacements.length
}
expressions`);

replacements.forEach(({node, newText}) => {
const span = document.createElement('span');
span.innerHTML = newText.replace(/\n/g, '
');
node.parentElement.replaceChild(span, node);
});

if (window.MathJax && window.MathJax.typesetPromise && replacements.length > 0) {
console.log('🎨 Rendering...');
MathJax.typesetPromise().then(() => {
console.log('✓ Complete');
}).catch(err =>  console.error('❌ Error:', err));
}
}

if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
setTimeout(convertMath, 1000);
});
} else {
setTimeout(convertMath, 1000);
}

let debounceTimer;
const observer = new MutationObserver(() => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(convertMath, 500);
});

setTimeout(() => {
observer.observe(document.body, {
childList: true,
subtree: true
});
}, 2000);
})();


Что мне следует исправить? Он не распознает текст должным образом, а упаковка делает его нечитаемым. Больше, чем раньше.

Подробнее здесь: https://stackoverflow.com/questions/798 ... ex-mathjax
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»