const regex = /(?<!\\) # negative look-behind to make sure start is not escaped
(?: # start non-capture group for all possible match starts
# group 1, match dollar signs only
# single or double dollar sign enforced by look-arounds
((?<!\$)\${1,2}(?!\$))|
# group 2, match escaped parenthesis
(\\\()|
# group 3, match escaped bracket
(\\\[)|
# group 4, match begin equation
(\\begin\{equation\})
)
# if group 1 was start
(?(1)
# non greedy match everything in between
# group 1 matches do not support recursion
(.*?)(?<!\\)
# match ending double or single dollar signs
(?<!\$)\1(?!\$)|
# else
(?:
# greedily and recursively match everything in between
# groups 2, 3 and 4 support recursion
(.*(?R)?.*)(?<!\\)
(?:
# if group 2 was start, escaped parenthesis is end
(?(2)\\\)|
# if group 3 was start, escaped bracket is end
(?(3)\\\]|
# else group 4 was start, match end equation
\\end\{equation\}
)
))))/gm;
// Alternative syntax using RegExp constructor
// const regex = new RegExp('(?<!\\\\) # negative look-behind to make sure start is not escaped
(?: # start non-capture group for all possible match starts
# group 1, match dollar signs only
# single or double dollar sign enforced by look-arounds
((?<!\\$)\\${1,2}(?!\\$))|
# group 2, match escaped parenthesis
(\\\\\\()|
# group 3, match escaped bracket
(\\\\\\[)|
# group 4, match begin equation
(\\\\begin\\{equation\\})
)
# if group 1 was start
(?(1)
# non greedy match everything in between
# group 1 matches do not support recursion
(.*?)(?<!\\\\)
# match ending double or single dollar signs
(?<!\\$)\\1(?!\\$)|
# else
(?:
# greedily and recursively match everything in between
# groups 2, 3 and 4 support recursion
(.*(?R)?.*)(?<!\\\\)
(?:
# if group 2 was start, escaped parenthesis is end
(?(2)\\\\\\)|
# if group 3 was start, escaped bracket is end
(?(3)\\\\\\]|
# else group 4 was start, match end equation
\\\\end\\{equation\\}
)
))))', 'gm')
const str = `NOTE: For test purposes each test has been contained to one line, please enable the s flag for multi-line matches.
\$ match \$ don't match nested \$ match \$
\$\$ no match\$
\$no match\$\$
\\\\\$no match\\\\\$
\$no match\\\\\$
\\\\\$no match\\\\\$
\$\$ match \$\$ don't match nested \$\$ match \$\$
\$\$\$ no match \$\$
\$\$ no match \$\$\$
\\\\\$\$ no match\$\$
\$\$ no match\\\\\$\$
\\\\\$\$ no match\\\\\$\$
\\( match \\)
\\( 1 \\( nested match \\) 3 \\)
\\\\( no match \\\\)
\\( no match \\\\\\\\)
\\\\\\\\( no match \\\\\\\\)
\\[ match \\]
\\[ 1 \\[ nested match \\] 3 \\]
\\\\\\\\[ no match \\\\]
\\\\[ no match \\\\\\\\]
\\\\\\\\[ no match \\\\\\\\]
\\begin{equation} match \\end{equation}
\\begin{equation} 1 \\begin{equation} nested match \\end{equation} \\end{equation}
\\\\\\\\begin{equation} no match \\\\end{equation}
\\\\begin{equation} no match \\\\\\\\end{equation}
\\\\\\\\begin{equation} no match \\\\end{equation}`;
// Reset `lastIndex` if this regex is defined globally
// regex.lastIndex = 0;
let m;
while ((m = regex.exec(str)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
// The result can be accessed through the `m`-variable.
m.forEach((match, groupIndex) => {
console.log(`Found match, group ${groupIndex}: ${match}`);
});
}
Please keep in mind that these code samples are automatically generated and are not guaranteed to work. If you find any syntax errors, feel free to submit a bug report. For a full regex reference for JavaScript, please visit: https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions