用python编写表达式求值_用Python3实现表达式求值
Problem Description yizhen has no girlfriend due to his stupid brain that he even can’t solve a simple arithmetic roblem. Can you help him If you solve it and tell him the result, then he can find his lovers! So beautiful! Input The input
一、題目描述
請用 python3編寫一個(gè)計(jì)算器的控制臺(tái)程序,支持加減乘除、乘方、括號(hào)、小數(shù)點(diǎn),運(yùn)算符優(yōu)先級(jí)為括號(hào)>乘方>乘除>加減,同級(jí)別運(yùn)算按照從左向右的順序計(jì)算。
二、輸入描述
數(shù)字包括"0123456789",小數(shù)點(diǎn)為".",運(yùn)算符包括:加("+")、減("-")、乘("*")、除("/")、乘方("^",注:不是**!)、括號(hào)("()")
需要從命令行參數(shù)讀入輸入,例如提交文件為 main.py,可以用 python3?main.py "1+2-3+4" 的方式進(jìn)行調(diào)用
輸入需要支持空格,即?python3?main.py "1 ? ? + ? ? 2 ? ? ?- ? ? 3 ? ?+ ? ?4" 也需要程序能夠正確給出結(jié)果
所有測試用例中參與運(yùn)算的非零運(yùn)算數(shù)的絕對值范圍保證在 10^9-10^(-10) 之內(nèi), 應(yīng)該輸出運(yùn)算結(jié)果時(shí)非零運(yùn)算結(jié)果絕對值也保證在該范圍內(nèi)
三、輸出描述
數(shù)字需要支持小數(shù)點(diǎn),輸出結(jié)果取10位有效數(shù)字,有效數(shù)字位數(shù)不足時(shí)不能補(bǔ)0
對于不在輸入描述內(nèi)的輸入,輸出INPUT ERROR
對于格式不合法(例如括號(hào)不匹配等)的輸入,輸出 FORMAT ERROR
對于不符合運(yùn)算符接收的參數(shù)范圍(例如除0等)的輸入,輸出VALUE ERROR
對于2、3、4的情況,輸出即可,不能拋出異常
同時(shí)滿足2、3、4中多個(gè)條件時(shí),以序號(hào)小的為準(zhǔn)
四、樣例
輸入: 1 + 2 - 3 + 4
輸出: 4
輸入: 1 + 2 - 3 + 1 / 3
輸出: 0.3333333333
輸入: 1 + + 2
輸出: FORMAT ERROR
輸入: 1 / 0
輸出: VALUE ERROR
輸入: a + 1
輸出: INPUT ERROR
【注:此題為TsinghuaX:34100325X 《軟件工程》 MOOC 課程 Spring, 2016 Chapter 1 Problem,此文發(fā)布時(shí),這門課剛剛在 “學(xué)堂在線” 上開課兩天】
代碼是先看了 http://blog.csdn.net/whos2002110/article/details/19119449 這個(gè)網(wǎng)址的。然后 自己記憶寫了一份。 本來目的是要學(xué)一些 解釋器的。雖然也看到一些實(shí)現(xiàn),但是感覺對我有點(diǎn)難度,于是從簡單開始學(xué)習(xí)。 import java.util.ArrayList;import java.
用 Python3 實(shí)現(xiàn),初看一下,首先想到的其實(shí)是一種“討巧”(作弊 >_
大致代碼區(qū)區(qū)幾行:
1 from sys import argv
2
3 if __name__ == "__main__":
4 exp = argv[1]
5 print(eval(exp))
即便是考慮到題干中的輸出要求做異常處理(try...except)輸出相應(yīng)的錯(cuò)誤信息,也就十行左右。
但稍深入就會(huì)發(fā)現(xiàn),有些情形還是無法按要求處理的,比如樣例 “1 + + 2”,用 eval() 會(huì)輸出結(jié)果 “3” (+2 前的 “+” 被當(dāng)作正號(hào)),而題目要求輸出 “FORMAT ERROR”。
沒辦法,只能老老實(shí)實(shí)做苦力活兒了。
表達(dá)式求值其實(shí)是《數(shù)據(jù)結(jié)構(gòu)》課程里一個(gè)基本且重要的問題之一,一般作為 “棧” 的應(yīng)用來提出。
問題的關(guān)鍵就是需要按照人們通常理解的運(yùn)算符的優(yōu)先級(jí)來進(jìn)行計(jì)算,而在計(jì)算過程中的臨時(shí)結(jié)果則用 棧 來存儲(chǔ)。
為此,我們可以首先構(gòu)造一個(gè) “表” 來存儲(chǔ)當(dāng)不同的運(yùn)算符 “相遇” 時(shí),它們誰更 “屌” 一些(優(yōu)先級(jí)更高一些)。這樣就可以告訴計(jì)算機(jī),面對不同的情形,它接下來應(yīng)該如何來處理。
其次,我們需要構(gòu)造兩個(gè)棧,一個(gè)運(yùn)算符棧,一個(gè)運(yùn)算數(shù)棧。
運(yùn)算符棧是為了搞定當(dāng)某個(gè)運(yùn)算符優(yōu)先級(jí)較低時(shí),暫時(shí)先讓它呆在棧的底部位置,待它可以 “重見天日” 的那一天(優(yōu)先級(jí)相對較高時(shí)),再把它拿出來使用。正確計(jì)算完成后,此棧應(yīng)為空。
運(yùn)算數(shù)棧則是為了按合理的計(jì)算順序存儲(chǔ)運(yùn)算中間結(jié)果。正確計(jì)算完成后,此棧應(yīng)只剩下一個(gè)數(shù),即為最后的結(jié)果。
完整的代碼如下:
1 # -*- coding: utf-8 -*-
2
3 #################################
4 # @Author: Maples7
5 # @LaunchTime: 2016/2/24 12:32:38
6 # @FileName: main
7 # @Email: maples7@163.com
8 # @Function:
9 #
10 # A Python Calculator for Operator +-*/()^
11 #
12 #################################
13
14 from sys import argv
15 from decimal import *
16
17 def delBlank(str):
18 """
19 Delete all blanks in the str
20 """
21 ans = ""
22 for e in str:
23 if e != " ":
24 ans += e
25 return ans
26
27 def precede(a, b):
28 """
29 Compare the prior of operator a and b
30 """
31 # the prior of operator
32 prior = (
33 # '+' '-' '*' '/' '(' ')' '^' '#'
34 ('>', '>', '', ''), # '+'
35 ('>', '>', '', ''), # '-'
36 ('>', '>', '>', '>', '', ''), # '*'
37 ('>', '>', '>', '>', '', ''), # '/'
38 ('
39 ('>', '>', '>', '>', ' ', '>', '>', '>'), # ')'
40 ('>', '>', '>', '>', '', '>', '>'), # '^'
41 ('
42 )
43
44 # operator to index of prior[8][8]
45 char2num = {
46 '+': 0,
47 '-': 1,
48 '*': 2,
49 '/': 3,
50 '(': 4,
51 ')': 5,
52 '^': 6,
53 '#': 7
54 }
55
56 return prior[char2num[a]][char2num[b]]
57
58 def operate(a, b, operator):
59 """
60 Operate [a operator b]
61 """
62 if operator == '+':
63 ans = a + b
64 elif operator == '-':
65 ans = a - b
66 elif operator == '*':
67 ans = a * b
68 elif operator == '/':
69 if b == 0:
70 ans = "VALUE ERROR"
71 else:
72 ans = a / b
73 elif operator == '^':
74 if a == 0 and b == 0:
75 ans = "VALUE ERROR"
76 else:
77 ans = a ** b
78
79 return ans
80
81 def calc(exp):
82 """
83 Calculate the ans of exp
84 """
85 exp += '#'
86 operSet = "+-*/^()#"
87 stackOfOperator, stackOfNum = ['#'], []
88 pos, ans, index, length = 0, 0, 0, len(exp)
89 while index < length:
90 e = exp[index]
91 if e in operSet:
92 # calc according to the prior
93 topOperator = stackOfOperator.pop()
94 compare = precede(topOperator, e)
95 if compare == '>':
96 try:
97 b = stackOfNum.pop()
98 a = stackOfNum.pop()
99 except:
100 return "FORMAT ERROR"
101 ans = operate(a, b, topOperator)
102 if ans == "VALUE ERROR":
103 return ans
104 else:
105 stackOfNum.append(ans)
106 elif compare == '
107 stackOfOperator.append(topOperator)
108 stackOfOperator.append(e)
109 index += 1
110 elif compare == '=':
111 index += 1
112 elif compare == ' ':
113 return "FORMAT ERROR"
114 else:
115 # get the next num
116 pos = index
117 while not exp[index] in operSet:
118 index += 1
119 temp = exp[pos:index]
120
121 # delete all 0 of float in the end
122 last = index - 1
123 if '.' in temp:
124 while exp[last] == '0':
125 last -= 1
126 temp = exp[pos:last + 1]
127
128 try:
129 temp = Decimal(temp)
130 except:
131 return "INPUT ERROR"
132 stackOfNum.append(temp)
133
134 if len(stackOfNum) == 1 and stackOfOperator == []:
135 return stackOfNum.pop()
136 else:
137 return "INPUT ERROR"
138
139 if __name__ == "__main__":
140 # get the exp
141 exp = argv[1]
142
143 # set the precision
144 getcontext().prec = 10
145
146 # delete blanks
147 exp = delBlank(exp)
148
149 # calc and print the ans
150 ans = calc(exp)
151 print(ans)
其中需要稍微注意的細(xì)節(jié)有:
1. 表達(dá)式處理前,前后都插入一個(gè) '#' 作為一個(gè)特殊的運(yùn)算符,這樣做是為了方便統(tǒng)一處理,即不用再去特別判斷表達(dá)式是否已經(jīng)結(jié)束(從而引發(fā)一系列邊界問題導(dǎo)致代碼冗長復(fù)雜,這種處理也可稱之為 “哨兵” 技巧)。如果最后兩個(gè)運(yùn)算符相遇則說明表達(dá)式處理完畢,這個(gè)運(yùn)算符的優(yōu)先級(jí)也是最低的(在 prior 表中也有體現(xiàn))。
2. 輸出要求比較復(fù)雜,拋去錯(cuò)誤信息輸出不說(只能具體情況具體分析),不能輸出多余的0,折騰了一會(huì)兒最后發(fā)現(xiàn)用高精度的?Decimal 可以完美滿足題目要求。
3. 由于不能輸出多余的0,所以在帶有小數(shù)部分的數(shù)字 “錄入” 時(shí)(代碼115-132行),就要把一些多余的0提前去掉(代碼121-126行),比如 2.0 這樣的情況。
總結(jié)
以上是生活随笔為你收集整理的用python编写表达式求值_用Python3实现表达式求值的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Makefile由浅入深完全学习记录5
- 下一篇: python怎么用lambda和map函