如何用Python校验字符串类型的数学表达式是否合法
Python 校验仅含数字的合法数学表达式方案
完全可以用Python现有库实现,无需自行开发完整的词法、语法校验逻辑,以下是两种成熟的实现方式:
方法1:使用内置ast模块(推荐,无需安装第三方依赖)
ast是Python标准库自带的抽象语法树模块,仅解析表达式不执行代码,安全性高,完全适配需求。
实现代码
import ast import operator # 可按需扩展允许的运算符,比如支持乘方可加ast.Pow ALLOWED_OPERATORS = { ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul, ast.Div: operator.truediv, ast.USub: operator.neg # 支持负号写法,比如-2 } def is_valid_num_expression(exp: str) -> bool: # 第一步校验语法合法性,括号不匹配、表达式不完整直接报错 try: tree = ast.parse(exp, mode='eval') except SyntaxError: return False # 第二步校验仅含数字和允许的运算符,无字母、变量等非法内容 def _check_node(node): if isinstance(node, ast.Expression): return _check_node(node.body) elif isinstance(node, ast.BinOp): # 二元运算,校验运算符和左右操作数 return type(node.op) in ALLOWED_OPERATORS and _check_node(node.left) and _check_node(node.right) elif isinstance(node, ast.UnaryOp): # 一元运算,校验运算符和操作数 return type(node.op) in ALLOWED_OPERATORS and _check_node(node.operand) elif isinstance(node, ast.Constant): # 常量必须为数字类型,Python3.8以下版本替换为ast.Num判断即可 return isinstance(node.value, (int, float)) else: # 遇到变量、函数调用等其他节点直接返回不合法 return False return _check_node(tree)
测试效果
print(is_valid_num_expression("(5+5)-(5)+(-2)")) # True print(is_valid_num_expression("(5+5)/2-1")) # True print(is_valid_num_expression("(5+5)/(3-1)")) # True print(is_valid_num_expression("(5+5)/(3-1")) # False print(is_valid_num_expression("5+")) # False print(is_valid_num_expression("(5+5)/()")) # False print(is_valid_num_expression("(a+b)/5")) # False
方法2:使用第三方sympy库(适合后续需要计算表达式值的场景)
如果需求除了校验之外还要对合法表达式做计算,可以用sympy的表达式解析能力,只需额外执行pip install sympy安装即可。
实现代码
from sympy import parse_expr def is_valid_num_expression_sympy(exp: str) -> bool: try: # 传入空的变量字典,遇到字母、变量会直接抛出异常 expr_obj = parse_expr(exp, local_dict={}) # 二次校验没有未定义的符号变量 return len(expr_obj.free_symbols) == 0 except: return False
校验通过后直接调用expr_obj.evalf()就能得到表达式的计算结果。
注意:不要直接用
eval()做校验,存在恶意代码执行风险,以上两种方案都是仅解析不执行,安全性有保障。
内容的提问来源于stack exchange,提问作者PaulRuban
相关产品推荐
相关产品推荐

