Published
Edited
Mar 2, 2021
Importers
1 star
Insert cell
Insert cell
Insert cell
example = (await fetch(
"https://gist.githubusercontent.com/bryangingechen/e340aa91244e730798a39156f371e89a/raw/46d1d5caf0cde719293414cc04ff56f892c37529/system_of_equations.md"
)).text()
Insert cell
example2 = removeMath(example, '$')
Insert cell
example2.text
Insert cell
example2.math
Insert cell
replaceMath(example2.text, example2.math)
Insert cell
SPLIT = /(\$\$?|\\(?:begin|end)\{[a-z]*\*?\}|\\[\\{}$]|[{}]|(?:\n\s*)+|@@\d+@@|`+)/i
Insert cell
capturingStringSplit = function(str, regex) {
return str.split(regex);
}
Insert cell
//
// Break up the text into its component parts and search
// through them for math delimiters, braces, linebreaks, etc.
// Math delimiters must match and braces must balance.
// Don't allow math to pass through a double linebreak
// (which will be a paragraph).
// Handle backticks (don't do math inside them)
//
function removeMath(text, inline) {
//
// The math is in blocks i through j, so
// collect it into one block and clear the others.
// Replace &, <, and > by named entities.
// For IE, put <br> at the ends of comments since IE removes \n.
// Clear the current math positions and store the index of the
// math, then push the math string onto the storage array.
//
function processMath(i, j) {
var block = blocks
.slice(i, j + 1)
.join("")
.replace(/&/g, "&amp;") // use HTML entity for &
.replace(/</g, "&lt;") // use HTML entity for <
.replace(/>/g, "&gt;"); // use HTML entity for >
if (indent) block = block.replace(/\n /g, "\n");
// if (HUB.Browser.isMSIE) {
// block = block.replace(/(%[^\n]*)\n/g, "$1<br/>\n");
// }
while (j > i) blocks[j--] = "";
blocks[i] = "@@" + math.length + "@@";
math.push(block);
start = end = last = null;
}
let start = null;
let end = null;
let last = null;
let indent = null; // for tracking math delimiters
let braces = null;
const math = []; // stores math strings for latter

let blocks = capturingStringSplit(text.replace(/\r\n?/g, "\n"), SPLIT);

for (var i = 1, m = blocks.length; i < m; i += 2) {
var block = blocks[i];
if (block.charAt(0) === "@") {
//
// Things that look like our math markers will get
// stored and then retrieved along with the math.
//
blocks[i] = "@@" + math.length + "@@";
math.push(block);
} else if (start) {
//
// If we are in math or backticks,
// look for the end delimiter,
// but don't go past double line breaks,
// and balance braces within the math,
// but don't process math inside backticks.
//
if (block === end) {
if (braces > 0) {
last = i;
} else if (braces === 0) {
processMath(start, i);
} else {
start = end = last = null;
}
} else if (block.match(/\n.*\n/) || i + 2 >= m) {
if (last) {
i = last;
if (braces >= 0) processMath(start, i);
}
start = end = last = null;
braces = 0;
} else if (block === "{" && braces >= 0) {
braces++;
} else if (block === "}" && braces > 0) {
braces--;
}
} else {
//
// Look for math start delimiters and when
// found, set up the end delimiter.
//
if (block === inline || block === "$$") {
start = i;
end = block;
braces = 0;
} else if (block.substr(1, 5) === "begin") {
start = i;
end = "\\end" + block.substr(6);
braces = 0;
} else if (block.charAt(0) === "`") {
start = last = i;
end = block;
braces = -1; // no brace balancing
} else if (block.charAt(0) === "\n") {
if (block.match(/ $/)) indent = true;
}
}
}
if (last) processMath(start, last);

// the commonmark renderer will render any `\$` as a simple `$`
// which could become a problem if `$` is used as a mathjax inline delimiter
// because then even escaped equations (starting with `\$`) would be detected
// as mathjax equations. Let's double-escape to make sure we still have a `\$`
// after commonmark did its conversion.
function doubleEscapeDelimiters(text, inline) {
if (!inline.startsWith("\\")) {
return text.replace(/\\\$/g, '\\\\$');
}
return text;
}

return { text: doubleEscapeDelimiters(blocks.join(""), inline), math };
}
Insert cell
//
// Put back the math strings that were saved,
// and clear the math array (no need to keep it around).
//
function replaceMath(input, math) {
const text = input.replace(/@@(\d+)@@/g, function(match, n) {
return math[n];
});
// math = null;
return text;
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more