1. 计算器
任务说明
实现一个支持加、减、乘、除和括号的简单计算器。用户输入一个数学表达式字符串(如 "2 + 3 * (4 - 1)"),程序解析该表达式并输出计算结果。本案例使用递归下降解析法,不依赖 eval(),保证表达式解析过程透明可控。
实现思路
采用递归下降解析器,将表达式文法定义为:
- expression:处理加减运算(最低优先级)
- term:处理乘除运算
- factor:处理数字、括号、正负号
解析器从左到右扫描输入字符串,跳过空格,按优先级逐层解析。除法使用浮点数运算,若除数为零则抛出异常提示。
代码实现
class Calculator:
"""递归下降解析器实现的计算器"""
def __init__(self, expression: str):
self.tokens = list(expression.replace(" ", ""))
self.pos = 0
def parse(self) -> float:
"""解析完整表达式并返回结果"""
if not self.tokens:
raise ValueError("表达式为空")
result = self._expression()
if self.pos != len(self.tokens):
raise ValueError(f"无法解析的字符: {self.tokens[self.pos]}")
return result
def _expression(self) -> float:
"""处理加减运算"""
value = self._term()
while self.pos < len(self.tokens):
op = self.tokens[self.pos]
if op in ('+', '-'):
self.pos += 1
right = self._term()
value = value + right if op == '+' else value - right
else:
break
return value
def _term(self) -> float:
"""处理乘除运算"""
value = self._factor()
while self.pos < len(self.tokens):
op = self.tokens[self.pos]
if op in ('*', '/'):
self.pos += 1
right = self._factor()
if op == '*':
value *= right
else:
if right == 0:
raise ZeroDivisionError("除数不能为零")
value /= right
else:
break
return value
def _factor(self) -> float:
"""处理数字、括号和正负号"""
if self.pos >= len(self.tokens):
raise ValueError("表达式不完整")
= self.tokens[self.pos]
# 处理一元正负号
if in ('+', '-'):
self.pos += 1
val = self._factor()
return val if == '+' else -val
# 处理括号
if == '(':
self.pos += 1
val = self._expression()
if self.pos >= len(self.tokens) or self.tokens[self.pos] != ')':
raise ValueError("缺少右括号")
self.pos += 1
return val
# 处理数字(支持整数和小数)
if .isdigit() or == '.':
start = self.pos
while self.pos < len(self.tokens) and (self.tokens[self.pos].isdigit() or self.tokens[self.pos] == '.'):
self.pos += 1
num_str = ''.join(self.tokens[start:self.pos])
try:
return float(num_str)
except ValueError:
raise ValueError(f"无效数字: {num_str}")
raise ValueError(f"无法识别的字符: {}")
def main():
"""交互式入口:读取用户输入并计算结果"""
while True:
try:
expr = input("请输入表达式(输入 q 退出): ").strip()
if expr.lower() == 'q':
break
if not expr:
continue
calc = Calculator(expr)
result = calc.parse()
# 输出整数时不带小数点
if result == int(result):
print(f"结果: {int(result)}")
else:
print(f"结果: {result}")
except (ValueError, ZeroDivisionError) as e:
print(f"错误: {e}")
if __name__ == "__main__":
main()
运行与验证
运行方式:将代码保存为 calculator.py,在终端执行 python calculator.py,然后输入表达式进行测试。
验证用例与预期输出:
输入: 2 + 3 * 4
输出: 14
输入: (2 + 3) * 4
输出: 20
输入: 10 / 4
输出: 2.5
输入: -3 + 5
输出: 2
输入: 2 * (3 + 4) - 6 / 2
输出: 11
输入: 5 / 0
输出: 错误: 除数不能为零
输入: (1 + 2
输出: 错误: 缺少右括号
判定标准:上述用例的输出与预期一致,且程序能正确处理括号嵌套、运算符优先级、一元正负号及除零错误,即判定实现通过。
解析过程示意
解析器从最外层的 expression 开始,遇到加减号则继续处理右侧的 term;term 内部处理乘除;遇到括号时递归调用 _expression() 解析括号内子表达式。这种层级结构天然保证了运算优先级:先括号、再乘除、最后加减。