1. 程式人生 > 實用技巧 >python-陣列+遞迴實現簡單代數式運算

python-陣列+遞迴實現簡單代數式運算


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#思路:
#代數式是為字串
#先將字串處理為數值與運算子號的陣列
#逐項讀入陣列
#每一次處理不少過兩個變數,一個運算子(cos,lg等為單變數運算,使用Var2,+_*?等為雙運算子)
#當讀入的第二運算子優先於當前運算子,發生遞迴呼叫;否則將計算當權運算子與兩個變數並返回為一個變數,運算允許無運算子,只返回Var1
#()優先順序最高,出現(發生遞迴呼叫,表示為Ture,)出現則計算當前運算並返回根層次計算
#lg(5)發生一次運算,lg(5+2)則需要兩次運算先做5+2,在做lg7
#即當運算子為單變數運算入sin,cos,lg等,遞迴呼叫,表示為Flase,)出現,計算兩次,第一次擴號運算,第二次為單變數運算
#全部處理完陣列後,可能仍需一次運算
#1、strsplit(strAlgebraic=''): #將輸入的預算字串分割為便變數和運算子組成的陣列
#2、getprority(stropr=''): #輸入運算子,輸出優先順序數值
#3、calculation(operation ='',var1=0 ,var2=0): #已知變數,運算子,求得運算結構
#lg,sin,cos ,tg,ctg只需要變數2
#沒有運算子號返回變數一
#+,-,*,/,%等需要兩個變數
#4、Algebraicoperation(isleftbrac=False,var1=None,var2=None,opr=None,AlgebraicList=[],curpos=0 ):
#isleftbrac 左括號呼叫標識
#var1 ,var2 變數
#opr當前運算子
#代數運算陣列AlgebraicList
#陣列中當前位置
import math

operationnames = ["(",")",'sin(','cos(','tg(','ctg(','lg(','^','*','%','/','+','-'] #運算父字典
operationprority=[0,0,1,1,1,1,1,1,2,2,2,3,3] #運算子號優先順序,與operationnames對應,優先順序數值越小優先
#AlgebraicList=[]
def getprority(stropr=''): #輸入運算子,輸出優先順序數值
global operationnames
global operationprority
tmp=operationnames.index(stropr)
if tmp ==None :
print('未發現與%s匹配的運算子!'%stropr)
else:
return operationprority[tmp]
def calculation(operation ='',var1=0 ,var2=0): #已知變數,運算子,求得運算結構
#lg,sin,cos ,tg,ctg只需要變數2
#沒有運算子號返回變數一
#+,-,*,/,%等需要兩個變數
if operation=='^':
try:
return var1 **var2
except (ValueError, ArithmeticError):
print("程式發生了數字格式異常、算術異常之一")
except:
print("未知異常")
if operation=='+':
return float(var1)+float(var2)
if operation=='%':
try:
return var1%var2
except (ValueError, ArithmeticError):
print("程式發生了數字格式異常、算術異常之一")
except:
print("未知異常")

if operation=='/':
try:
return var1/var2
except (ValueError, ArithmeticError):
print("程式發生了數字格式異常、算術異常之一")
except:
print("未知異常")

if operation=='-':
return var1-var2
if operation=='*':
return var1*var2
if operation=='lg(':
try:
return math.log10(var2)
except (ValueError, ArithmeticError):
print("程式發生了數字格式異常、算術異常之一")
except:
print("未知異常")
if operation =='sin(':
return math.sin(var2)
if operation=='cos(':
return math.cos(var2)
if operation=='tg(':
return math.tan(var2)
if operation=='ctg(':
return 1/math.tan(var2)
if operation==None:
return var1

def Algebraicoperation(isleftbrac=False,var1=None,var2=None,opr=None,AlgebraicList=[],curpos=0 ):
#根據輸入的計算序列 陣列,遞迴計算
global operationnames
global operationprority
while curpos <len(AlgebraicList):
if AlgebraicList[curpos] not in operationnames: #當前值不是運算子
if var1 ==None and opr==None:#如果第一變數為空且當前運算子為空時,賦值與第一變數
var1=AlgebraicList[curpos]
else:
var2=AlgebraicList[curpos]#否則賦值第二變數
curpos=curpos+1 #取AlgebraicList下一值
else:
if AlgebraicList[curpos]=='(': #如果為(
if opr==None:#且唯有運算子則遞迴呼叫心的Algebraicoperation,返回值賦予第一變數
var1,curpos=Algebraicoperation(True,None,None,None,AlgebraicList,curpos+1)
else:#否則賦值第二變數
var2,curpos=Algebraicoperation(True,None,None,None,AlgebraicList,curpos+1)
elif AlgebraicList[curpos]in ['lg(','cos(','sin(','tg(','ctg(',]: #如果為單變數運算
if opr == None:#且第一編練為空,遞迴呼叫新的AlgebraicList,返回與第一變數
var1, curpos = Algebraicoperation(True, None, None, AlgebraicList[curpos], AlgebraicList, curpos +1)
else:#否則返回與第二bl
var2, curpos = Algebraicoperation(True, None, None, AlgebraicList[curpos], AlgebraicList, curpos +1)
elif AlgebraicList[curpos] == ')':#右擴號
if isleftbrac :#為對稱左括號
#if opr in ['lg(','log(','cos(','sin(','tg(','ctg(',]:#opr為單變數計算
# return calculation(opr, var1, var2),curpos+1
#else:
return calculation(opr, var1, var2), curpos+1
else:
return calculation(opr, var1, var2),curpos #注意不移動位置,目的是多使用一邊)
#例如:sin(a+b),右擴號多使用一邊,第一次計算a,b的和,第二次sin和
elif opr==None:#沒有當前運算子
opr=AlgebraicList[curpos] #賦值與當前運算子
curpos=curpos+1
else:
if getprority(AlgebraicList[curpos])>=getprority(opr) : #當新獲得運算不優先於已有運算子
if opr not in ['lg(','log(','cos(','sin(','tg(','ctg(',]: #且已有運算不是單變數運算時
var1=calculation(opr,var1,var2)#執行已有運算子
opr=AlgebraicList[curpos]
var2=None
curpos=curpos+1
else:
var2,curpos=Algebraicoperation(False,var2,None,AlgebraicList[curpos],AlgebraicList,curpos+1) #否則遞迴呼叫新的Algebraicoperation
else:
var2,curpos=Algebraicoperation(False,var2,None,AlgebraicList[curpos],AlgebraicList,curpos+1) #當新獲得運算優先於已有運算子,呼叫新的Algebraicoperation
return calculation(opr,var1,var2) #最後返回計算結果

def strsplit(strAlgebraic=''): #將輸入的預算字串分割為便變數和運算子組成的陣列
AlgebraicList=[]
tmpvar=''
tmpopr=''
for i in strAlgebraic:
if i in ['+','-','*','/','^','%',')']:
if tmpvar !='':
if '.'in tmpvar:
tmpvar=float(tmpvar)
else:
tmpvar=int(tmpvar)
AlgebraicList.append(tmpvar)
tmpvar=''
AlgebraicList.append(i)
if i.isdigit():
tmpvar=tmpvar+i
if i=='.':
tmpvar=tmpvar+i
if i =='(':
if tmpopr!='':
if tmpopr in ['lg','sin','cos','ctg','tg']:
tmpopr=tmpopr+i
AlgebraicList.append(tmpopr)
tmpopr=''
else:
print('不可識別%s計算符號!'%tmpopr)
return
else:
AlgebraicList.append(i)
if i.isalpha():
tmpopr=tmpopr+i.lower()
if tmpvar !='':
if '.' in tmpvar:
tmpvar = float(tmpvar)
else:
tmpvar = int(tmpvar)
AlgebraicList.append(tmpvar)
return AlgebraicList


print(strsplit('tg(((cos(54-51)+lg(24))))*2'))

print(Algebraicoperation(False,None,None,None,strsplit('tg(((cos(54-51)+lg(24))))*2'),0))