diff --git a/anki/media.py b/anki/media.py index 9cac9d78b..def118c77 100644 --- a/anki/media.py +++ b/anki/media.py @@ -232,23 +232,27 @@ create table meta (dirMod int, lastUsn int); insert into meta values (0, 0); l.append(fname) return l - def _expandClozes(self, string) -> List[str]: + def _expandClozes(self, string: str) -> List[str]: ords = set(re.findall(r"{{c(\d+)::.+?}}", string)) strings = [] - from anki.template.template import clozeReg + from anki.template.template import ( + clozeReg, + CLOZE_REGEX_MATCH_GROUP_HINT, + CLOZE_REGEX_MATCH_GROUP_CONTENT, + ) def qrepl(m): - if m.group(4): - return "[%s]" % m.group(4) + if m.group(CLOZE_REGEX_MATCH_GROUP_HINT): + return "[%s]" % m.group(CLOZE_REGEX_MATCH_GROUP_HINT) else: return "[...]" def arepl(m): - return m.group(2) + return m.group(CLOZE_REGEX_MATCH_GROUP_CONTENT) for ord in ords: s = re.sub(clozeReg % ord, qrepl, string) - s = re.sub(clozeReg % ".+?", "\\2", s) + s = re.sub(clozeReg % ".+?", arepl, s) strings.append(s) strings.append(re.sub(clozeReg % ".+?", arepl, string)) return strings diff --git a/anki/template/template.py b/anki/template/template.py index 8194e5720..b96936458 100644 --- a/anki/template/template.py +++ b/anki/template/template.py @@ -5,7 +5,17 @@ from anki.hooks import runFilter from anki.utils import stripHTML, stripHTMLMedia # Matches a {{c123::clozed-out text::hint}} Cloze deletion, case-insensitively. -clozeReg = r"(?si)\{\{(c)%s::(.*?)(::(.*?))?\}\}" +# The regex should be interpolated with a regex number and creates the following +# named groups: +# - tag: The lowercase or uppercase 'c' letter opening the Cloze. +# - content: Clozed-out content. +# - hint: Cloze hint, if provided. +clozeReg = r"(?si)\{\{(?Pc)%s::(?P.*?)(::(?P.*?))?\}\}" + +# Constants referring to group names within clozeReg. +CLOZE_REGEX_MATCH_GROUP_TAG = "tag" +CLOZE_REGEX_MATCH_GROUP_CONTENT = "content" +CLOZE_REGEX_MATCH_GROUP_HINT = "hint" modifiers: Dict[str, Callable] = {} @@ -96,7 +106,7 @@ class Template: txt = get_or_attr(context, m.group(2), None) m = re.search(clozeReg % m.group(1), txt) if m: - val = m.group(1) + val = m.group(CLOZE_REGEX_MATCH_GROUP_TAG) else: val = get_or_attr(context, section_name, None) @@ -201,9 +211,11 @@ class Template: return txt @classmethod - def clozeText(cls, txt, ord, type) -> str: + def clozeText(cls, txt: str, ord: str, type: str) -> str: + """Processe the given Cloze deletion within the given template.""" reg = clozeReg - if not re.search(reg % ord, txt): + currentRegex = clozeReg % ord + if not re.search(currentRegex, txt): # No Cloze deletion was found in txt. return "" txt = cls._removeFormattingFromMathjax(txt, ord) @@ -211,18 +223,18 @@ class Template: def repl(m): # replace chosen cloze with type if type == "q": - if m.group(4): - buf = "[%s]" % m.group(4) + if m.group(CLOZE_REGEX_MATCH_GROUP_HINT): + buf = "[%s]" % m.group(CLOZE_REGEX_MATCH_GROUP_HINT) else: buf = "[...]" else: - buf = m.group(2) + buf = m.group(CLOZE_REGEX_MATCH_GROUP_CONTENT) # uppercase = no formatting - if m.group(1) == "c": + if m.group(CLOZE_REGEX_MATCH_GROUP_TAG) == "c": buf = "%s" % buf return buf - txt = re.sub(reg % ord, repl, txt) + txt = re.sub(currentRegex, repl, txt) # and display other clozes normally return re.sub(reg % r"\d+", "\\2", txt)