MrJun's Blog

String with Formula Translated to HTML

将带有$$、$分隔符的字符串转化为Html。

原问题链接:https://github.com/KaTeX/KaTeX/issues/604。

参考代码:

最终实现代码:

// strngRender.js

import katex from 'katex';

const findEndOfMath = function(delimiter, text, startIndex) {
    let index = startIndex;
    let braceLevel = 0;

    const delimLength = delimiter.length;

    while (index < text.length) {
        const character = text[index];

        if (braceLevel <= 0 &&
            text.slice(index, index + delimLength) === delimiter) {
            return index;
        } else if (character === "\\") {
            index++;
        } else if (character === "{") {
            braceLevel++;
        } else if (character === "}") {
            braceLevel--;
        }

        index++;
    }

    return -1;
};

const escapeRegex = function(string) {
    return string.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
};

const amsRegex = /^\\begin{/;

const splitAtDelimiters = function(text, delimiters) {
    let index;
    const data = [];

    const regexLeft = new RegExp(
        "(" + delimiters.map((x) => escapeRegex(x.left)).join("|") + ")"
    );

    while (true) {
        index = text.search(regexLeft);
        if (index === -1) {
            break;
        }
        if (index > 0) {
            data.push({
                type: "text",
                data: text.slice(0, index),
            });
            text = text.slice(index);
        }
        const i = delimiters.findIndex((delim) => text.startsWith(delim.left));
        index = findEndOfMath(delimiters[i].right, text, delimiters[i].left.length);
        if (index === -1) {
            break;
        }
        const rawData = text.slice(0, index + delimiters[i].right.length);
        const math = amsRegex.test(rawData)
            ? rawData
            : text.slice(delimiters[i].left.length, index);
        data.push({
            type: "math",
            data: math,
            rawData,
            display: delimiters[i].display,
			delimiter: delimiters[i].right
        });
        text = text.slice(index + delimiters[i].right.length);
    }

    if (text !== "") {
        data.push({
            type: "text",
            data: text,
        });
    }

    return data;
};

const strngRender = function(text) {
	let data = splitAtDelimiters(text,
		[
			{left: '$$', right: '$$', display: true},
			{left: '$', right: '$', display: false},
			{left: '\\(', right: '\\)', display: false},
			{left: '\\[', right: '\\]', display: true}
		],
	)
	let res = ''
	for (let i = 0; i < data.length; i++) {
		if (data[i].type === "text") {
			res += data[i].data.replace("\n\n","<br/>");
		} else {
			let html = katex.renderToString(data[i].data, {
			    throwOnError: false
			});
			if(data[i].delimiter == '$$'){
				html = "<br/><p style='width:100%;text-align:center;'>"+html+"</p>"
			}
			res += html;
		}
	}
	return res;
}

export default strngRender;
// 使用方式

import strngRender from 'stringRender.js'
let strings = strngRender("hhh$c = \\pm\\sqrt{a^2 + b^2}$\n\n$$\na=b\n$$")