From bf74b85f6419916a2c75bbc5e7871e8b0f1b7b83 Mon Sep 17 00:00:00 2001 From: Bubu-Droid Date: Sun, 17 Aug 2025 02:38:19 +0530 Subject: [PATCH 1/2] Add more demacros --- von/strparse.py | 141 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 122 insertions(+), 19 deletions(-) diff --git a/von/strparse.py b/von/strparse.py index 1e55fc2..1212671 100644 --- a/von/strparse.py +++ b/von/strparse.py @@ -1,9 +1,80 @@ +#!/usr/bin/env python3 + import re +import pyperclip + +oper_macros = { + "\\floor": (" \\left\\lfloor ", " \\right\\rfloor "), + "\\ceil": (" \\left\\lceil ", " \\right\\rceil "), + "\\abs": (" \\left\\lvert ", " \\right\\lvert "), + "\\norm": (" \\left\\lVert ", " \\right\\lVert "), + "\\anbr": (" \\left\\langle ", " \\right\\rangle "), + "\\sbr": (" \\left[ ", " \\right] "), +} +derv_macros = { + "\\dd": "\\mathrm{d}", + "\\pd": "\\partial", +} + + +def bracket_cpos(text: str, brac: tuple, pos: int) -> int: + close_counter = 0 + open_counter = 1 + charpos = pos + 1 + for i in text[pos + 1 :]: + if i == brac[0]: + open_counter += 1 + elif i == brac[1]: + close_counter += 1 + if close_counter == open_counter: + break + charpos += 1 + return charpos + + +def derv_demacro(text: str) -> str: + for key, value in derv_macros.items(): + while text.find(key) != -1: + pos = text.find(key) + if text[pos + len(key)] == "{": + first_cur_cpos = bracket_cpos(text, ("{", "}"), pos + len(key)) + second_cur_cpos = bracket_cpos(text, ("{", "}"), first_cur_cpos + 1) + inner_text_1 = text[pos + len(key) + 1 : first_cur_cpos] + inner_text_2 = text[first_cur_cpos + 2 : second_cur_cpos] + text = ( + text[:pos] + + f"\\frac{{{value} {inner_text_1}}}{{{value} {inner_text_2}}}" + + text[second_cur_cpos + 1 :] + ) + elif text[pos + len(key)] == "[": + sq_cpos = bracket_cpos(text, ("[", "]"), pos + len(key)) + first_cur_cpos = bracket_cpos(text, ("{", "}"), sq_cpos + 1) + second_cur_cpos = bracket_cpos(text, ("{", "}"), first_cur_cpos + 1) + func_deg = text[pos + len(key) + 1 : sq_cpos] + inner_text_1 = text[sq_cpos + 2 : first_cur_cpos] + inner_text_2 = text[first_cur_cpos + 2 : second_cur_cpos] + text = ( + text[:pos] + + f"\\frac{{{value}^{{{func_deg}}} {inner_text_1}}}{{{value} {inner_text_2}^{{{func_deg}}}}}" + + text[second_cur_cpos + 1 :] + ) + return text -# Demacro -def demacro(text: str) -> str: - # TODO this doesn't quite work, but oh well + +def oper_demacro(text: str) -> str: + for key, value in oper_macros.items(): + while text.find(key) != -1: + pos = text.find(key) + cur_cpos = bracket_cpos(text, ("{", "}"), pos + len(key)) + inner_text_1 = text[pos + len(key) + 1 : cur_cpos] + text = ( + text[:pos] + value[0] + inner_text_1 + value[1] + text[cur_cpos + 1 :] + ) + return text + + +def comm_demacro(text: str) -> str: replacements: list[tuple[str, str]] = [ (r"\ii ", r"\item "), (r"\ii[", r"\item["), @@ -18,12 +89,12 @@ def demacro(text: str) -> str: (r"\half", r"\frac{1}{2}"), (r"\GL", r"\operatorname{GL}"), (r"\SL", r"\operatorname{SL}"), - (r"\NN", r"{\mathbb N}"), - (r"\ZZ", r"{\mathbb Z}"), - (r"\CC", r"{\mathbb C}"), - (r"\RR", r"{\mathbb R}"), - (r"\QQ", r"{\mathbb Q}"), - (r"\FF", r"{\mathbb F}"), + # (r"\NN", r"{\mathbb N}"), + # (r"\ZZ", r"{\mathbb Z}"), + # (r"\CC", r"{\mathbb C}"), + # (r"\RR", r"{\mathbb R}"), + # (r"\QQ", r"{\mathbb Q}"), + # (r"\FF", r"{\mathbb F}"), (r"\ts", r"\textsuperscript"), (r"\opname", r"\operatorname"), (r"\defeq", r"\overset{\text{def}}{=}"), @@ -32,6 +103,29 @@ def demacro(text: str) -> str: (r"\sign", r"\operatorname{sign}"), (r"\injto", r"\hookrightarrow"), (r"\vdotswithin=", r"\vdots"), + # Bubu additions + (r"\csc", r"\operatorname{cosec}"), + (r"\arccsc", r"\operatorname{arccsc}"), + (r"\arcsec", r"\operatorname{arcsec}"), + (r"\arccot", r"\operatorname{arccot}"), + (r"\ul", r"\underline"), + (r"\tri", r"\triangle"), + (r"\para", r"\parallel"), + (r"\arc", r"\widehat"), + (r"\hrulebar", "\n-----\n"), + (r"\CC", r"\mathbb{C}"), + (r"\FF", r"\mathbb{F}"), + (r"\NN", r"\mathbb{N}"), + (r"\QQ", r"\mathbb{Q}"), + (r"\RR", r"\mathbb{R}"), + (r"\ZZ", r"\mathbb{Z}"), + (r"\OO", r"\mathcal{O}"), + (r"\ang", r"\ang"), + (r"\ray", r"\overrightarrow"), + (r"\trans", r"^{\mathsf{T}}"), + (r"\oo", r"\infty"), + (r"\dgnin", r"90^{\circ}"), + (r"\dgone", r"180^{\circ}"), ] s = text for short, full in replacements: @@ -41,7 +135,7 @@ def demacro(text: str) -> str: def remove_soft_newlines(text: str) -> str: return re.sub( - r"[a-zA-Z.,;—\"–'):]\n[a-zA-Z$]", + r"[a-zA-Z.,;—\"–'):$]\n[a-zA-Z$]", lambda m: m.group(0).replace("\n", " "), text, ) @@ -49,7 +143,9 @@ def remove_soft_newlines(text: str) -> str: def toAOPS(text: str) -> str: DIVIDER = "\n" + r"-------------------" + "\n\n" - text = demacro(text) + text = derv_demacro(text) + text = oper_demacro(text) + text = comm_demacro(text) text = text.replace(r"\qedhere", "") text = text.replace(r"\begin{asy}", "\n" + "[asy]" + "\n") text = text.replace(r"\end{asy}", "\n" + "[/asy]") @@ -95,7 +191,7 @@ def toAOPS(text: str) -> str: text = re.sub(r"\\textit{([^}]*)}", r"[i]\1[/i]", text) text = re.sub(r"\\textbf{([^}]*)}", r"[b]\1[/b]", text) text = re.sub( - r"\\paragraph{([^}]*)}", DIVIDER + r"[color=blue][b]\1[/b][/color]", text + r"\\paragraph{([^}]*)}", DIVIDER + r"[color=blue][b]\1[/b][/solor]", text ) text = re.sub(r"\\subparagraph{([^}]*)}", DIVIDER + r"[b]\1[/b]", text) text = re.sub(r"\\url{([^}]*)}", r"[url]\1[/url]", text) @@ -103,11 +199,18 @@ def toAOPS(text: str) -> str: text = re.sub( r"\\item\[([^\]]*)\]", r"[*] [b]\1[/b]", text ) # for description items - text = text.replace(r"\arc", r"\widehat") - # Join together newlines - paragraphs = [ - " ".join([line.strip() for line in paragraph.splitlines()]).strip() - for paragraph in text.split("\n\n") - ] - return "\n".join(paragraphs) + return text + # # Join together newlines + # paragraphs = [ + # " ".join([line.strip() for line in paragraph.splitlines()]).strip() + # for paragraph in text.split("\n\n") + # ] + # return "\n".join(paragraphs) + + +if __name__ == "__main__": + cliptext = pyperclip.paste() + cliptext = remove_soft_newlines(cliptext) + cliptext = toAOPS(cliptext) + pyperclip.copy(cliptext) From 4f1eca931d2815fbcff0c52772a94bd41df44bb9 Mon Sep 17 00:00:00 2001 From: Bubu-Droid Date: Thu, 21 Aug 2025 16:52:25 +0530 Subject: [PATCH 2/2] Make requested fixes --- von/strparse.py | 100 ++++++++---------------------------------------- 1 file changed, 16 insertions(+), 84 deletions(-) diff --git a/von/strparse.py b/von/strparse.py index 1212671..b350206 100644 --- a/von/strparse.py +++ b/von/strparse.py @@ -1,9 +1,5 @@ -#!/usr/bin/env python3 - import re -import pyperclip - oper_macros = { "\\floor": (" \\left\\lfloor ", " \\right\\rfloor "), "\\ceil": (" \\left\\lceil ", " \\right\\rceil "), @@ -12,10 +8,6 @@ "\\anbr": (" \\left\\langle ", " \\right\\rangle "), "\\sbr": (" \\left[ ", " \\right] "), } -derv_macros = { - "\\dd": "\\mathrm{d}", - "\\pd": "\\partial", -} def bracket_cpos(text: str, brac: tuple, pos: int) -> int: @@ -33,35 +25,6 @@ def bracket_cpos(text: str, brac: tuple, pos: int) -> int: return charpos -def derv_demacro(text: str) -> str: - for key, value in derv_macros.items(): - while text.find(key) != -1: - pos = text.find(key) - if text[pos + len(key)] == "{": - first_cur_cpos = bracket_cpos(text, ("{", "}"), pos + len(key)) - second_cur_cpos = bracket_cpos(text, ("{", "}"), first_cur_cpos + 1) - inner_text_1 = text[pos + len(key) + 1 : first_cur_cpos] - inner_text_2 = text[first_cur_cpos + 2 : second_cur_cpos] - text = ( - text[:pos] - + f"\\frac{{{value} {inner_text_1}}}{{{value} {inner_text_2}}}" - + text[second_cur_cpos + 1 :] - ) - elif text[pos + len(key)] == "[": - sq_cpos = bracket_cpos(text, ("[", "]"), pos + len(key)) - first_cur_cpos = bracket_cpos(text, ("{", "}"), sq_cpos + 1) - second_cur_cpos = bracket_cpos(text, ("{", "}"), first_cur_cpos + 1) - func_deg = text[pos + len(key) + 1 : sq_cpos] - inner_text_1 = text[sq_cpos + 2 : first_cur_cpos] - inner_text_2 = text[first_cur_cpos + 2 : second_cur_cpos] - text = ( - text[:pos] - + f"\\frac{{{value}^{{{func_deg}}} {inner_text_1}}}{{{value} {inner_text_2}^{{{func_deg}}}}}" - + text[second_cur_cpos + 1 :] - ) - return text - - def oper_demacro(text: str) -> str: for key, value in oper_macros.items(): while text.find(key) != -1: @@ -74,7 +37,7 @@ def oper_demacro(text: str) -> str: return text -def comm_demacro(text: str) -> str: +def demacro(text: str) -> str: replacements: list[tuple[str, str]] = [ (r"\ii ", r"\item "), (r"\ii[", r"\item["), @@ -89,12 +52,12 @@ def comm_demacro(text: str) -> str: (r"\half", r"\frac{1}{2}"), (r"\GL", r"\operatorname{GL}"), (r"\SL", r"\operatorname{SL}"), - # (r"\NN", r"{\mathbb N}"), - # (r"\ZZ", r"{\mathbb Z}"), - # (r"\CC", r"{\mathbb C}"), - # (r"\RR", r"{\mathbb R}"), - # (r"\QQ", r"{\mathbb Q}"), - # (r"\FF", r"{\mathbb F}"), + (r"\CC", r"\mathbb{C}"), + (r"\FF", r"\mathbb{F}"), + (r"\NN", r"\mathbb{N}"), + (r"\QQ", r"\mathbb{Q}"), + (r"\RR", r"\mathbb{R}"), + (r"\ZZ", r"\mathbb{Z}"), (r"\ts", r"\textsuperscript"), (r"\opname", r"\operatorname"), (r"\defeq", r"\overset{\text{def}}{=}"), @@ -103,29 +66,7 @@ def comm_demacro(text: str) -> str: (r"\sign", r"\operatorname{sign}"), (r"\injto", r"\hookrightarrow"), (r"\vdotswithin=", r"\vdots"), - # Bubu additions - (r"\csc", r"\operatorname{cosec}"), - (r"\arccsc", r"\operatorname{arccsc}"), - (r"\arcsec", r"\operatorname{arcsec}"), - (r"\arccot", r"\operatorname{arccot}"), - (r"\ul", r"\underline"), - (r"\tri", r"\triangle"), - (r"\para", r"\parallel"), (r"\arc", r"\widehat"), - (r"\hrulebar", "\n-----\n"), - (r"\CC", r"\mathbb{C}"), - (r"\FF", r"\mathbb{F}"), - (r"\NN", r"\mathbb{N}"), - (r"\QQ", r"\mathbb{Q}"), - (r"\RR", r"\mathbb{R}"), - (r"\ZZ", r"\mathbb{Z}"), - (r"\OO", r"\mathcal{O}"), - (r"\ang", r"\ang"), - (r"\ray", r"\overrightarrow"), - (r"\trans", r"^{\mathsf{T}}"), - (r"\oo", r"\infty"), - (r"\dgnin", r"90^{\circ}"), - (r"\dgone", r"180^{\circ}"), ] s = text for short, full in replacements: @@ -135,7 +76,7 @@ def comm_demacro(text: str) -> str: def remove_soft_newlines(text: str) -> str: return re.sub( - r"[a-zA-Z.,;—\"–'):$]\n[a-zA-Z$]", + r"[a-zA-Z.,;—\"–'):$]\n[a-zA-Z$'\"]", lambda m: m.group(0).replace("\n", " "), text, ) @@ -143,9 +84,8 @@ def remove_soft_newlines(text: str) -> str: def toAOPS(text: str) -> str: DIVIDER = "\n" + r"-------------------" + "\n\n" - text = derv_demacro(text) text = oper_demacro(text) - text = comm_demacro(text) + text = demacro(text) text = text.replace(r"\qedhere", "") text = text.replace(r"\begin{asy}", "\n" + "[asy]" + "\n") text = text.replace(r"\end{asy}", "\n" + "[/asy]") @@ -191,7 +131,7 @@ def toAOPS(text: str) -> str: text = re.sub(r"\\textit{([^}]*)}", r"[i]\1[/i]", text) text = re.sub(r"\\textbf{([^}]*)}", r"[b]\1[/b]", text) text = re.sub( - r"\\paragraph{([^}]*)}", DIVIDER + r"[color=blue][b]\1[/b][/solor]", text + r"\\paragraph{([^}]*)}", DIVIDER + r"[color=blue][b]\1[/b][/color]", text ) text = re.sub(r"\\subparagraph{([^}]*)}", DIVIDER + r"[b]\1[/b]", text) text = re.sub(r"\\url{([^}]*)}", r"[url]\1[/url]", text) @@ -200,17 +140,9 @@ def toAOPS(text: str) -> str: r"\\item\[([^\]]*)\]", r"[*] [b]\1[/b]", text ) # for description items - return text - # # Join together newlines - # paragraphs = [ - # " ".join([line.strip() for line in paragraph.splitlines()]).strip() - # for paragraph in text.split("\n\n") - # ] - # return "\n".join(paragraphs) - - -if __name__ == "__main__": - cliptext = pyperclip.paste() - cliptext = remove_soft_newlines(cliptext) - cliptext = toAOPS(cliptext) - pyperclip.copy(cliptext) + # Join together newlines + paragraphs = [ + " ".join([line.strip() for line in paragraph.splitlines()]).strip() + for paragraph in text.split("\n\n") + ] + return "\n".join(paragraphs)