1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
| import re import tkinter as tk from tkinter import ttk from sympy.parsing.latex import parse_latex from sympy import Integral, Sum, Symbol import pyttsx3
class LatexTranslator: def __init__(self): self.symbol_map = { r'\alpha': 'alpha', r'\beta': 'beta', r'\gamma': 'gamma', r'\delta': 'delta', r'\epsilon': 'epsilon', r'\zeta': 'zeta', r'\eta': 'eta', r'\theta': 'theta', r'\iota': 'iota', r'\kappa': 'kappa', r'\lambda': 'lambda', r'\mu': 'mu', r'\nu': 'nu', r'\xi': 'xi', r'\pi': 'pi', r'\rho': 'rho', r'\sigma': 'sigma', r'\tau': 'tau', r'\upsilon': 'upsilon', r'\phi': 'phi', r'\chi': 'chi', r'\psi': 'psi', r'\omega': 'omega', r'\times': 'times', r'\div': 'divided by', r'\pm': 'plus or minus', r'\mp': 'minus or plus', r'\cdot': 'dot', r'\ast': 'asterisk', r'\circ': 'circle', r'\bullet': 'bullet', r'\oplus': 'o-plus', r'\otimes': 'o-times', r'\leq': 'less than or equal to', r'\geq': 'greater than or equal to', r'\neq': 'not equal to', r'\equiv': 'equivalent to', r'\approx': 'approximately equal to', r'\in': 'in', r'\subset': 'subset', r'\cup': 'union', r'\cap': 'intersection', r'\exists': 'there exists', r'\forall': 'for all', r'\neg': 'not', r'\lor': 'or', r'\land': 'and', r'\nabla': 'nabla', r'\partial': 'partial', r'\hbar': 'h-bar', r'\ell': 'script l', r'\infty': 'infinity', r'\angle': 'angle', r'\triangle': 'triangle', r'\square': 'square', r'\diamond': 'diamond' } self.structure_rules = [ (r'\\frac\{(.*?)\}\{(.*?)\}', r'\1 over \2'), (r'\\dfrac\{(.*?)\}\{(.*?)\}', r'\1 over \2'), (r'(\d+)/(\d+)', r'\1 over \2'), (r'\\sqrt\{(.*?)\}', r'square root of \1'), (r'\\sqrt\[(\d+)\]\{(.*?)\}', r'\1-th root of \2'), (r'\\int_\{?(.*?)\}?\{(.*?)\}', r'integral from \1 to \2 of'), (r'\\sum_\{?(.*?)\}?\{(.*?)\}', r'sum from \1 to \2 of'), (r'\\lim_\{(.+?)\}', r'limit as \1 approaches'),
(r'\\sin\{(.*?)\}', r'sine of \1'), (r'\\cos\{(.*?)\}', r'cosine of \1'), (r'\\tan\{(.*?)\}', r'tangent of \1'),
(r'e\^\{?(.*?)\}?', r'exponential of \1'), (r'\\ln\{(.*?)\}', r'natural logarithm of \1'), (r'\\log_\{?(.*?)\}?\{(.*?)\}', r'logarithm base \1 of \2'),
(r'(\w+)\^\{?(.*?)\}?', r'\1 to the power of \2'), (r'(\w+)_\{?(.*?)\}?', r'\1 subscript \2') ] def parse_with_sympy(self, latex_str): """使用SymPy解析复杂结构 至于能不能分析对 我也不知道""" try: expr = parse_latex(latex_str) if isinstance(expr, Integral): var = expr.variables[0]() return f"integral from {expr.limits[0]()[1]()} to {expr.limits[0]()[2]()} of {self._parse_expr(expr.function)} d{var}" elif isinstance(expr, Sum): index = expr.limits[0]()[0]() return f"sum from {index}={expr.limits[0]()[1]()} to {expr.limits[0]()[2]()} of {self._parse_expr(expr.function)}" return self._parse_expr(expr) except: return self.basic_convert(latex_str)
def _parse_expr(self, expr): """递归解析SymPy表达式 至于能不能解析对 我也不知道""" if isinstance(expr, Symbol): return expr.name args = [self._parse_expr(a) for a in expr.args] return f"{expr.func.__name__} of {' '.join(args)}"
def basic_convert(self, latex_str): """基础正则转换 至于能不能转换对 我也不知道""" for _ in range(5): for pattern, repl in self.structure_rules: latex_str = re.sub(pattern, repl, latex_str) for sym, eng in self.symbol_map.items(): latex_str = latex_str.replace(sym, eng) return latex_str
class TranslatorApp: def __init__(self): self.translator = LatexTranslator() self.window = tk.Tk() self.window.title("LaTeX 翻译器 ( 支持输入中文+LaTeX → 输出中文+英文 ) --ZejunFu") self.input = tk.Text(self.window, height=20, width=50, wrap=tk.WORD) self.output = tk.Text(self.window, height=20, width=50, wrap=tk.WORD, state='disabled') self.input.grid(row=0, column=0, padx=10, pady=10) self.output.grid(row=0, column=1, padx=10, pady=10) self.btn_frame = ttk.Frame(self.window) self.btn_frame.grid(row=1, column=0, columnspan=2) ttk.Button(self.btn_frame, text="read it(超绝机器音)", command=self.speak).pack(side=tk.LEFT) self.input.bind('<KeyRelease>', lambda e: self.update_output())
def update_output(self): """更新翻译结果""" latex = self.input.get("1.0", tk.END).strip() result = self.translator.parse_with_sympy(latex) self.output.config(state='normal') self.output.delete("1.0", tk.END) self.output.insert(tk.END, result) self.output.config(state='disabled')
def speak(self): """语音朗读""" try: engine = pyttsx3.init() engine.say(self.output.get("1.0", tk.END)) engine.runAndWait() except Exception as e: print("语音功能需要pyttsx3库支持 拿到代码的大家要是没有的话自己去下吧 或者用exe")
if __name__ == "__main__": app = TranslatorApp() app.window.mainloop()
|