1. 计算器
任务说明
实现一个支持加、减、乘、除和括号的简单计算器,能够解析用户输入的数学表达式(如 2 + 3 * (4 - 1))并输出计算结果。程序从命令行读取表达式,解析后打印结果。
实现思路
采用递归下降解析法:将表达式文法定义为 expr → term (('+'|'-') term)*,term → factor (('*'|'/') factor)*,factor → number | '(' expr ')'。解析器从左到右扫描输入,按优先级递归处理,除法使用浮点运算,遇到除数为零或非法字符时抛出明确错误。
代码实现
import sys
class Calculator:
def __init__(self, text):
self.text = text.replace(' ', '')
self.pos = 0
def parse(self):
if not self.text:
raise ValueError("空表达式")
result = self.expr()
if self.pos != len(self.text):
raise ValueError(f"无法解析的字符: '{self.text[self.pos]}'")
return result
def expr(self):
value = self.term()
while self.pos < len(self.text) and self.text[self.pos] in '+-':
op = self.text[self.pos]
self.pos += 1
rhs = self.term()
value = value + rhs if op == '+' else value - rhs
return value
def term(self):
value = self.factor()
while self.pos < len(self.text) and self.text[self.pos] in '*/':
op = self.text[self.pos]
self.pos += 1
rhs = self.factor()
if op == '*':
value *= rhs
else:
if rhs == 0:
raise ZeroDivisionError("除数为零")
value /= rhs
return value
def factor(self):
if self.pos < len(self.text) and self.text[self.pos] == '(':
self.pos += 1
value = self.expr()
if self.pos < len(self.text) and self.text[self.pos] == ')':
self.pos += 1
return value
raise ValueError("缺少右括号")
return self.number()
def number(self):
start = self.pos
while self.pos < len(self.text) and (self.text[self.pos].isdigit() or self.text[self.pos] == '.'):
self.pos += 1
if start == self.pos:
raise ValueError(f"位置 {self.pos} 处不是有效数字")
return float(self.text[start:self.pos])
if __name__ == '__main__':
if len(sys.argv) < 2:
print("用法: python calculator.py \"表达式\"")
sys.exit(1)
try:
result = Calculator(sys.argv[1]).parse()
# 若结果为整数则去掉小数点
print(f"{result:g}")
except (ValueError, ZeroDivisionError) as e:
print(f"错误: {e}")
sys.exit(1)
运行与验证
将上述代码保存为 calculator.py,在终端执行以下命令:
python calculator.py "2 + 3 * (4 - 1)"
python calculator.py "10 / 4"
python calculator.py "(1 + 2) * 3"
预期输出分别为 11、2.5、9。程序支持小数、嵌套括号与空格;输入非法字符、缺少括号或除数为零时,会输出以 错误: 开头的提示并退出。
判定标准
- 加减乘除四则运算结果正确,乘除优先级高于加减;
- 括号可改变运算顺序,支持嵌套括号;
- 表达式含空格时能正常解析;
- 非法输入(如
2+*3、(1+2、5/0)能给出明确错误信息而非崩溃。