1
import string

# Strength of operations:
#   -> [] (brackets)
# 6 -> ~ (negative)
# 5 -> @, $, & (average, maximum, minimum)
# 4 -> %, ! (modulo, factorial)
# 3 -> ^ (power)
# 2 -> *, / (multiplication, division)
# 1 -> +, - (addition, subtraction)

def BinaryOperation(exp, idx):
    """ Gets an expression and an index of an operator and returns a tuple with (first_value, operator, second_value). """
    first_value = 0
    second_value = 0

    #Get first value
    idx2 = idx -1
    if idx2 == 0:
        first_value = exp[idx2:idx]

    else:
        while (idx2 > 0) and (exp[idx2] in string.digits):
            idx2 -=1

        if (exp[idx2] in ("-")) or (exp[idx2] in string.digits):#-5*3
            first_value = exp[idx2:idx]
        else:#%5*3
            first_value = exp[idx2+1:idx]

    #Get second value
    idx2 = idx +1
    if exp[idx+1] not in string.digits: #If there is something like 1*+5, second_sign will be +.
        idx2 += 1 #idx2 will begin from the char after the sign.

    while (idx2 < len(exp)) and (exp[idx2] in string.digits):
        idx2 += 1

    second_value = exp[idx+1:idx2]

    return (first_value, exp[idx], second_value)

def UnaryOperation(exp, idx):
    """ Gets an expression and an index of an operator and returns a tuple with (operator, value). """
    #Get value
    idx2 = idx+1
    if exp[idx+1] not in string.digits: #If there is something like ~-5, second_sign will be -.
        idx2 += 1 #idx2 will begin from the char after the sign.
    while (idx2 < len(exp)) and (exp[idx2] in string.digits):
        idx2 +=1

    return (exp[idx], exp[idx+1:idx2])

def Brackets(exp):
    idx = 0
    while idx < len(exp):
        if exp[idx] == "[":
            #Brackets
            close_bracket = exp.find("]")
            if close_bracket == -1:
                raise Exception("Missing closing bracket.")

            exp_brackets = exp[idx+1:close_bracket]

            value = str(solve(exp_brackets))

            exp = exp.replace("[" + exp_brackets + "]", value)
            idx = 0 #The len has been changed, scan again.

        idx += 1

    return Level6(exp)

def Level6(exp):
    idx = 0
    while idx < len(exp):
        if exp[idx] in ("~"):
            #Negative
            sub_exp = UnaryOperation(exp, idx)
            value = ~int(sub_exp[1])

            value = str(value)

            exp = exp.replace(''.join(sub_exp), value)
            idx = 0 #The len has been changed, scan again.

        idx += 1
    return Level5(exp)

def Level5(exp):
    idx = 0
    while idx < len(exp):
        if exp[idx] in ("@", "$", "&"):
            #Average, Maximum and Minimum
            sub_exp = BinaryOperation(exp, idx)
            first_value = int(sub_exp[0])
            second_value = int(sub_exp[2])
            if sub_exp[1] == "@":
                value = (first_value + second_value)/2
            if sub_exp[1] == "$":
                value = first_value if first_value > second_value else second_value
            if sub_exp[1] == "&":
                value = first_value if first_value < second_value else second_value

            value = str(value)

            exp = exp.replace(''.join(sub_exp), value)
            idx = 0 #The len has been changed, scan again.

        idx += 1

    return Level4(exp)

def Level4(exp):
    idx = 0
    while idx < len(exp):
        if exp[idx] in ("%","!"):
            #Modulo and Factorial
            if exp[idx] == "%":
                sub_exp = BinaryOperation(exp, idx)
                value = int(sub_exp[0]) % int(sub_exp[2])
            if exp[idx] == "!":
                sub_exp = UnaryOperation(exp, idx)
                value = reduce(lambda x,y:x*y, range(1, int(sub_exp[1])+1))


            value = str(value)

            exp = exp.replace(''.join(sub_exp), value)
            idx = 0 #The len has been changed, scan again.

        idx += 1

    return Level3(exp)

def Level3(exp):
    idx = 0
    while idx < len(exp):
        if exp[idx] in ("^"):
            #Power
            sub_exp = BinaryOperation(exp, idx)
            value = int(sub_exp[0]) ** int(sub_exp[2])

            value = str(value)

            exp = exp.replace(''.join(sub_exp), value)
            idx = 0 #The len has been changed, scan again.

        idx += 1

    return Level2(exp)


def Level2(exp):
    idx = 0
    while idx < len(exp):
        if exp[idx] in ("*", "/"):
            #Multiplication and Division
            sub_exp = BinaryOperation(exp, idx)
            if sub_exp[1] == "*":
                value = int(sub_exp[0]) * int(sub_exp[2])
            if sub_exp[1] == "/":
                value = int(sub_exp[0]) / int(sub_exp[2])

            value = str(value)

            exp = exp.replace(''.join(sub_exp), value)
            idx = 0 #The len has been changed, scan again.

        idx += 1

    return Level1(exp)

def Level1(exp):
    idx = 0
    while idx < len(exp):
        if (exp[idx] in ("+", "-")) and (idx != 0):
            #Addition and Subtraction
            sub_exp = BinaryOperation(exp, idx)
            if sub_exp[1] == "+":
                value = int(sub_exp[0]) + int(sub_exp[2])
            if sub_exp[1] == "-":
                value = int(sub_exp[0]) - int(sub_exp[2])

            value = str(value)

            exp = exp.replace(''.join(sub_exp), value)
            idx = 0 #The len has been changed, scan again.

        idx += 1

    return exp

def solve(exp):
    exp = Brackets(exp)
    return float(exp) if "." in exp else int(exp)

def remove_whitespace(exp):
    """ Gets a string and removes all whitespaces and tabs """
    exp = exp.replace(" ", "")
    exp = exp.replace("\t", "")
    return exp

while True:
    exp = raw_input("")
    exp = remove_whitespace(exp)
    print solve(exp)

私は多くの努力の末にこのプログラムを作成しましたが、そのソリューションの効率性と、それが適切かどうか疑問に思っていました。

だから私の質問は、このプログラムはどれほど単純で、それを書き直すより良い方法はありますか?

4

3 に答える 3

1

要点だけ。

>>> eval(raw_input("input calculation: "))
input calculation: 1+1
2
>>> eval(raw_input("input calculation: "))
input calculation: (6*4^2)
26
>>> eval(raw_input("input calculation: "))
input calculation: (3/2.3)*4
5.2173913043478262

無実のプログラムの場合、使用できますeval

しかし、あなたは本当にそれを使うべきではありません。その唯一の本当の用途は人々を混乱させることであり、自分でプログラムを書いて電卓が欲しいと決心した場合の楽しい目新しさです.

電卓関数を書く方法はたくさんあります。

これらの他の答えのいくつかを試してください:

Python で電卓を作成する

Python の基本的な電卓プログラム

Python 電卓プログラム

于 2012-12-04T14:46:25.670 に答える
1

Python でいくつかのカスタム クラスベースの評価エンジンを確認したい場合は、次のものが役立ちます。

于 2012-12-04T19:36:42.780 に答える