# coding=utf8
# the above tag defines encoding for this document and is for Python 2.x compatibility
import re
regex = r"""
(?<!\\) # 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\}
)
))))
"""
test_str = ("NOTE: For test purposes each test has been contained to one line, please enable the s flag for multi-line matches.\n\n"
"$ match $ don't match nested $ match $\n\n"
"$$ no match$\n"
"$no match$$\n"
"\\\\$no match\\\\$\n"
"$no match\\\\$\n"
"\\\\$no match\\\\$\n\n"
"$$ match $$ don't match nested $$ match $$\n\n"
"$$$ no match $$\n"
"$$ no match $$$\n"
"\\\\$$ no match$$\n"
"$$ no match\\\\$$\n"
"\\\\$$ no match\\\\$$\n\n"
"\\( match \\)\n"
"\\( 1 \\( nested match \\) 3 \\)\n\n"
"\\\\( no match \\\\)\n"
"\\( no match \\\\\\\\)\n"
"\\\\\\\\( no match \\\\\\\\)\n\n"
"\\[ match \\]\n"
"\\[ 1 \\[ nested match \\] 3 \\]\n\n"
"\\\\\\\\[ no match \\\\]\n"
"\\\\[ no match \\\\\\\\]\n"
"\\\\\\\\[ no match \\\\\\\\]\n\n"
"\\begin{equation} match \\end{equation}\n"
"\\begin{equation} 1 \\begin{equation} nested match \\end{equation} \\end{equation}\n\n"
"\\\\\\\\begin{equation} no match \\\\end{equation}\n"
"\\\\begin{equation} no match \\\\\\\\end{equation}\n"
"\\\\\\\\begin{equation} no match \\\\end{equation}")
matches = re.finditer(regex, test_str, re.MULTILINE | re.VERBOSE)
for matchNum, match in enumerate(matches, start=1):
print ("Match {matchNum} was found at {start}-{end}: {match}".format(matchNum = matchNum, start = match.start(), end = match.end(), match = match.group()))
for groupNum in range(0, len(match.groups())):
groupNum = groupNum + 1
print ("Group {groupNum} found at {start}-{end}: {group}".format(groupNum = groupNum, start = match.start(groupNum), end = match.end(groupNum), group = match.group(groupNum)))
# Note: for Python 2.7 compatibility, use ur"" to prefix the regex and u"" to prefix the test string and substitution.
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 Python, please visit: https://docs.python.org/3/library/re.html