如何在不使用eval()的情况下将字符串的用户输入求值为数学表达式



我需要制作一个程序,接受数学表达式的用户输入(expr(,并处理找到答案的问题。但是,我们不允许使用eval((函数。赋值指出,我们应该假设用户将输入的运算符只有:+、-、*、/、%。操作数也被假定为一位整数。

我的想法是将操作数转换为整数,并列出所有可以使用的运算符。然后,使用if语句查看操作符如何匹配我的列表。

到目前为止,我能够想出这些代码行:

operand1 = expr[1]
operator = expr[2]
operand2 = expr[3]
operators = ['+','-','*','/','%']

我这样做是为了索引输入表达式中每个操作数和运算符的位置。我被困在这里,希望有人能帮助我如何前进。代码的结果需要输出用户输入的表达式以及表达式的结果。如果表达式的第二个操作数是0,并且运算符是除法,则代码输出"None"。

您可以使用ast.parse解析表达式。

>>> import ast
>>> expr = ast.parse("3 + 5", mode="eval")

然后您可以分析生成的解析树。在这个特定的实例中,您关心表达式的主体。

>>> expr
<_ast.Expression object at 0x10992c438>
>>> expr.body
<_ast.BinOp object at 0x10a926320>

该对象具有感兴趣的属性:leftopright。你会看到操作员

>>> expr.body.op
<_ast.Add object at 0x10a91a208>

以决定如何处理操作数。

>>> expr.body.left.n + expr.body.right.n
8

因此,一个可以处理乘法和加法的简单递归函数可能看起来像

def evaluate_expr(expr):
if isinstance(expr, ast.Expression):
return evaluate_expr(expr.body)
elif isinstance(expr, ast.Num):
return expr.n
elif isinstance(expr, ast.BinOp):
op = expr.op
left = evaluate_expr(expr.left)
right = evaluate_expr(expr.right)
if isinstance(op, ast.Add):
return left + right
elif isinstance(op, ast.Mult):
return left * right
raise ValueError(f"Can't evaluate {expr}")
e = ast.parse("3 + 5 * 2", mode="eval")
print(evaluate_expr(e.body))  # Outputs 13

请参阅ast模块的文档,了解树中可以出现哪些其他节点,以便您可以调整evaluate_expr来处理其他操作、括号等。ast.dump对于探索如何解析表达式也很有用。

>>> ast.dump(e, annotate_fields=False)
'Expression(BinOp(Num(3), Add(), BinOp(Num(5), Mult(), Num(2))))'

这清楚地表明解析器处理优先级:3 + 5 * 2不是结果乘以2的3 + 5,而是3加上5 * 2的结果(较低的节点具有较高的优先级,因为树是从下往上计算的(。


这假设您的输入实际上是一个有效的Python表达式。如果没有,您将需要编写自己的解析器,但一旦您有了解析树,对该树的评估将以类似的方式进行(尽管树的节点是您在解析中创建的任何节点,而不一定是ast.Bin等人由ast.parse创建的节点(。

如果此输入字符串中只有一个运算符(例如5 + 9(,则首先列出要计算的所有运算符operators = ["+", "-", "*", "/", "%"]

然后你必须遍历这个列表中的每个运算符,如果它在字符串中,则继续

# I'm defining the string here manually but you can do it with input()
expression_string = "5 + 9"
for i in range(0, len(operators)):
if operators[i] in expression_string:
....

如果操作符在expression_string中,则首先必须将其拆分为两个操作数,并在浮动中转换这两个操作

operands = expression_string.split(operators[i])
# Converting the two numbers into floats
operands[0] = float(operands[0])
operands[1] = float(operands[1])

现在,最后一步是通过if循环遍历您想要计算的每个运算符并进行计算

if operators[i] == "+":
result = operands[0] + operands[1]
elif operators[i] == "-":
result = operands[0] - operands[1]
elif operators[i] == "*":
result = operands[0] * operands[1]
elif operators[i] == "/":
result = operands[0] / operands[1]
elif operators[i] == "%":
result = operands[0] % operands[1]

现在,这个字符串的结果存储在变量"中;结果";

我希望这能帮助你

EDIT:您只需在最后一个if循环下写入print(result)即可打印结果。也可以在循环elif operators[i] == "/"中检查操作数是否为0,然后将result保存为None

最新更新