"""公式解析异常定义。 提供清晰的错误信息,帮助用户快速定位公式解析问题。 """ import difflib from typing import List, Optional class FormulaParseError(Exception): """公式解析错误基类。 Attributes: expr: 原始表达式字符串 lineno: 错误所在行号(从1开始) col_offset: 错误所在列号(从0开始) """ def __init__( self, message: str, expr: Optional[str] = None, lineno: Optional[int] = None, col_offset: Optional[int] = None, ): self.expr = expr self.lineno = lineno self.col_offset = col_offset # 构建详细错误信息 full_message = self._format_message(message) super().__init__(full_message) def _format_message(self, message: str) -> str: """格式化错误信息,包含位置指示器。""" lines = [f"FormulaParseError: {message}"] if self.expr: lines.append(f" 公式: {self.expr}") # 添加错误位置指示器 if self.col_offset is not None and self.lineno is not None: # 计算错误行在表达式中的起始位置 expr_lines = self.expr.split("\n") if 1 <= self.lineno <= len(expr_lines): error_line = expr_lines[self.lineno - 1] lines.append(f" {error_line}") # 添加指向错误位置的箭头 pointer = " " * (self.col_offset + 7) + "^--- 此处出错" lines.append(pointer) return "\n".join(lines) class UnknownFunctionError(FormulaParseError): """未知函数错误。 当表达式中使用了未注册的函数时抛出。 Attributes: func_name: 未知的函数名 available: 可用函数列表 suggestions: 模糊匹配建议列表 """ def __init__( self, func_name: str, available: List[str], expr: Optional[str] = None, lineno: Optional[int] = None, col_offset: Optional[int] = None, ): self.func_name = func_name self.available = available # 使用 difflib 获取模糊匹配建议 self.suggestions = difflib.get_close_matches( func_name, available, n=3, cutoff=0.5 ) # 构建错误信息 if self.suggestions: suggestion_str = ", ".join(f"'{s}'" for s in self.suggestions) hint_msg = f"你是不是想找: {suggestion_str}?" else: # 只显示前10个可用函数 available_preview = ", ".join(available[:10]) if len(available) > 10: available_preview += f", ... 等共 {len(available)} 个函数" hint_msg = f"可用函数预览: {available_preview}" msg = f"未知函数 '{func_name}'。{hint_msg}" super().__init__( message=msg, expr=expr, lineno=lineno, col_offset=col_offset, ) class InvalidSyntaxError(FormulaParseError): """语法错误。 当表达式语法不正确或不支持时抛出。 """ pass class UnsupportedOperatorError(InvalidSyntaxError): """不支持的运算符错误。 当使用了不支持的运算符时抛出(如位运算、矩阵运算等)。 """ pass class EmptyExpressionError(FormulaParseError): """空表达式错误。""" def __init__(self): super().__init__("表达式不能为空或只包含空白字符") class RegistryError(Exception): """注册表错误基类。""" pass class DuplicateFunctionError(RegistryError): """函数重复注册错误。 当尝试注册已存在的函数且未设置 force=True 时抛出。 """ def __init__(self, func_name: str): self.func_name = func_name super().__init__( f"函数 '{func_name}' 已存在。使用 force=True 覆盖,或选择其他名称。" )