解析用户输入的表达式并计算结果
本文最后更新于 2025-10-28,文章内容可能已经过时。
提供两种安全有效的解决方案,用于解析和计算用户输入的数学表达式。
方案一:使用安全的数学表达式解析库(推荐)
最安全可靠的方法是使用专门的数学表达式解析库,如py-expression-eval。这个库专门设计用于安全地解析和计算数学表达式,避免了eval()的安全风险。
安装库
pip install py-expression-eval
代码实现
def calculate_expression():
expression_str = input("请输入一个数学表达式(例如:2 + 3 * 4):")
try:
# 使用py-expression-eval安全解析和计算表达式
from py_expression_eval import Parser
parser = Parser()
result = parser.parse(expression_str).evaluate({})
print(f"计算结果是:{result}")
except Exception as e:
print(f"表达式计算出错:{e}")
if __name__ == "__main__":
calculate_expression()
方案二:使用运算符优先级实现的解析器(安全替代方案)
若不想安装额外库,可以使用基于栈的运算符优先级解析方法。
def calculate_expression():
expression_str = input("请输入数学表达式(例如:2+3*4 或 2.5*(3-1)):")
# 预处理步骤 - 完全忽略空格,正确处理数字和运算符
tokens = []
current = ''
for char in expression_str:
# 忽略所有空格
if char == ' ':
continue
# 正确处理一元负号(如 -3, 2*-3)
if char == '-' and (not tokens or tokens[-1] in '(*+-/'):
current = '-'
continue
# 修复1:小数点位置检查(允许在开头或负号后)
if char == '.':
# 允许小数点在开头(.5)或负号后(-.5)
if not current or current[-1] not in '0123456789':
if current != '-' and not current: # 允许开头小数点
# 保留小数点,但不立即添加
pass
else:
# 负号后面可以跟小数点(如 -0.5)
pass
# 如果小数点位置合法,继续加入current
current += char
continue
# 修复2:将小数点从运算符列表中移除
if char in '()+-*/':
if current != '':
tokens.append(current)
current = ''
tokens.append(char)
else:
current += char
if current != '':
tokens.append(current)
# 验证所有token
valid_tokens = []
for token in tokens:
if token in '()+-*/':
valid_tokens.append(token)
else:
# 检查是否是合法数字(包括负数和小数)
if token.replace('.', '', 1).replace('-', '', 1).isdigit():
valid_tokens.append(token)
else:
# 修复3:特殊处理小数点开头的情况(如".5")
if token.startswith('.') and token[1:].replace('-', '', 1).isdigit():
valid_tokens.append(token)
else:
raise ValueError(f"无效的表达式元素: '{token}'")
tokens = valid_tokens
# 初始化栈
operand_stack = []
operator_stack = []
# 运算符优先级
def priority(op):
if op in ('+', '-'): return 1
if op in ('*', '/'): return 2
return 0
# 执行运算
def apply_op(a, b, op):
if op == '+': return a + b
if op == '-': return a - b
if op == '*': return a * b
if op == '/':
if b == 0:
raise ZeroDivisionError("除数不能为零")
return a / b
raise ValueError(f"未知运算符: {op}")
# 处理表达式
for token in tokens:
if token == '(':
operator_stack.append(token)
elif token == ')':
while operator_stack and operator_stack[-1] != '(':
op = operator_stack.pop()
b = operand_stack.pop()
a = operand_stack.pop()
operand_stack.append(apply_op(a, b, op))
if not operator_stack or operator_stack[-1] != '(':
raise ValueError("括号不匹配")
operator_stack.pop() # 移除 '('
elif token in '+-*/':
while (operator_stack and
operator_stack[-1] != '(' and
priority(operator_stack[-1]) >= priority(token)):
op = operator_stack.pop()
b = operand_stack.pop()
a = operand_stack.pop()
operand_stack.append(apply_op(a, b, op))
operator_stack.append(token)
else: # 数字
operand_stack.append(float(token))
# 处理剩余运算符
while operator_stack:
op = operator_stack.pop()
if op == '(':
raise ValueError("括号不匹配")
b = operand_stack.pop()
a = operand_stack.pop()
operand_stack.append(apply_op(a, b, op))
# 验证结果
if len(operand_stack) != 1:
raise ValueError("表达式无效")
result = operand_stack[0]
# 检查是否为整数(考虑浮点数精度)
if abs(result - round(result)) < 1e-5:
# 是整数,输出整数
print(f"计算结果是:{int(round(result))}")
else:
# 是小数,格式化输出(去掉末尾的0)
result_str = f"{result:.6f}"
# 去掉末尾的0
if '.' in result_str:
result_str = result_str.rstrip('0').rstrip('.')
print(f"计算结果是:{result_str}")
if __name__ == "__main__":
try:
calculate_expression()
except Exception as e:
print(f"错误: {str(e)}")
重要安全提示
强烈建议不要使用eval()函数直接执行用户输入,原因如下:
- 安全风险:
eval()可以执行任意Python代码,用户可能输入恶意代码(如删除文件、访问敏感数据等)
为什么推荐py-expression-eval?
- 安全性:专门设计用于安全解析数学表达式,不会执行任意代码
- 功能强大:支持多种运算符、常量和函数
- 易用性:API设计简洁直观
- 专业性:是专门为数学表达式求值设计的库
使用示例
请输入一个数学表达式(例如:2 + 3 * 4):2 + 3 * 4
计算结果是:14.0
如果您需要处理包含变量的表达式(如"x + y"),可以扩展上述代码,让用户输入变量的值:
def calculate_expression_with_variables():
expression_str = input("请输入一个包含变量的表达式(例如:x + y):")
x = float(input("请输入x的值:"))
y = float(input("请输入y的值:"))
try:
from py_expression_eval import Parser
parser = Parser()
result = parser.parse(expression_str).evaluate({'x': x, 'y': y})
print(f"计算结果是:{result}")
except Exception as e:
print(f"表达式计算出错:{e}")
py-expression-eval 是一个用于 Python 的数学表达式求值库,灵感来源于 JavaScript 库 js-expression-eval。它由 Vera Mazhuga 移植及修改以适应 Python 环境。该库提供了一个简洁的 API,允许开发者轻松地解析、评估和简化数学表达式,特别适合于后端验证场景,其中一致性和性能至关重要。许可证为 MIT,确保了广泛的应用可能性。
- 感谢你赐予我前进的力量
赞赏者名单
因为你们的支持让我意识到写文章的价值🙏
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 软件从业者Hort
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果

