[英]How to evaluate a user input of a string as a math expression without using eval()?
我需要制作一個程序來接受數學表達式的用戶輸入(expr)並處理找到答案。 但是,我們不允許使用 eval() function。 賦值聲明我們應該假設用戶將輸入的唯一運算符是:+、-、*、/、%。 操作數也被假定為一位整數。
我的想法是將操作數轉換為整數並列出所有可以使用的運算符。 然后,使用 if 語句查看運算符如何匹配我的列表。
到目前為止,我能夠想出這些代碼行:
operand1 = expr[1]
operator = expr[2]
operand2 = expr[3]
operators = ['+','-','*','/','%']
我這樣做是為了索引輸入表達式中每個操作數和運算符的位置。 我被困在這里,希望有人能給我一些關於如何前進的幫助。 代碼的結果需要output用戶輸入的表達式,以及表達式的結果。 如果表達式的第二個操作數是 0 並且運算符是除法,則代碼輸出“無”。
您可以使用ast.parse
解析表達式。
>>> import ast
>>> expr = ast.parse("3 + 5", mode="eval")
然后您可以分析生成的解析樹。 在這種特殊情況下,您關心表達式的主體。
>>> expr
<_ast.Expression object at 0x10992c438>
>>> expr.body
<_ast.BinOp object at 0x10a926320>
此 object 具有感興趣的屬性: left
、 op
和right
。 你會看運營商
>>> expr.body.op
<_ast.Add object at 0x10a91a208>
決定如何處理操作數。
>>> expr.body.left.n + expr.body.right.n
8
所以一個可以處理乘法和加法的簡單遞歸 function 可能看起來像
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
不是3 + 5
的結果乘以 2,而是3
加上5 * 2
的結果(較低的節點具有較高的優先級,因為樹是從自下而上)。
這假定您的輸入實際上是有效的 Python 表達式。 如果沒有,您將需要編寫自己的解析器,但是一旦有了解析樹,該樹的評估就會以類似的方式進行(盡管樹的節點是您在解析中創建的任何內容,不一定是ast.Bin
等人由ast.parse
創建的節點)。
如果您在此輸入字符串中只有一個運算符(例如5 + 9
),那么您首先制作一個包含所有要計算的運算符的列表operators = ["+", "-", "*", "/", "%"]
然后你必須通過此列表中的每個運算符 go ,如果它在字符串中,則 go 前面
# 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:
....
如果運算符在那個表達式字符串中,首先您必須將其拆分為兩個操作數並將它們都轉換為浮點數
operands = expression_string.split(operators[i])
# Converting the two numbers into floats
operands[0] = float(operands[0])
operands[1] = float(operands[1])
現在最后一步是 go 通過您想要使用 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]
現在您將這個字符串的結果存儲在變量“result”中
我希望這可以幫助你
編輯:您可以簡單地在最后一個 if 循環下編寫print(result)
來打印您的結果。 如果操作數為 0,您還可以檢查循環elif operators[i] == "/"
,然后將result
保存為None
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.