簡體   English   中英

如何在不使用 eval() 的情況下將字符串的用戶輸入評估為數學表達式?

[英]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 具有感興趣的屬性: leftopright 你會看運營商

>>> 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM