From 81e6ab5b1debe22dd31ad33fde71dd44e28bf883 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Tue, 20 Dec 2022 17:02:29 -0800 Subject: [PATCH] Add MTex.dirty_select A more general way to select subparts by tex. Not as reliable as select_parts, but useful in many cases. --- manimlib/mobject/svg/mtex_mobject.py | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/manimlib/mobject/svg/mtex_mobject.py b/manimlib/mobject/svg/mtex_mobject.py index 4cacdc93..b7adf2c4 100644 --- a/manimlib/mobject/svg/mtex_mobject.py +++ b/manimlib/mobject/svg/mtex_mobject.py @@ -209,6 +209,39 @@ class MTex(StringMobject): ): return self.set_parts_color_by_dict(color_map) + @staticmethod + def n_symbols(tex) -> int: + """ + This function attempts to estimate the number of symbols that + a given string of tex would produce. + + No guarantees this is accurate. + """ + count_to_subtrs = [ + (0, ["emph", "textbf", "big", "Big", "small", "Small"]), + (2, ["sqrt", "ne"]), + (6, ["underbrace"]), + # Replace all other \expressions (like "\pi") with a single character + # Deliberately put this last. + (1, ["[a-zA-Z]+"]) + ] + for count, substrs in count_to_subtrs: + # Replace occurances of the given substrings with `count` characters + pattern = "|".join((R"\\" + s for s in substrs )) + tex = re.sub(pattern, "X" * count, tex) + # Ignore various control characters + return len(list(filter(lambda c: c not in "^{} \n\t_", tex))) + + def dirty_select(self, substr: str) -> VGroup: + tex = self.get_tex() + result = [] + for match in re.finditer(substr.replace("\\", R"\\"), tex): + index = match.start() + start = self.n_symbols(tex[:index]) + end = start + self.n_symbols(substr) + result.append(self[start:end]) + return VGroup(*result) + def get_tex(self) -> str: return self.get_string()