功能分析
用戶輸入一個類似這樣 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) ) 這樣的表達式,假設表達式里面除了包含空格、'+'、'-'、'*'、'/'和括號再無其他特殊符號,然后自己動手寫代碼解析其中的表達式,實現加減乘除,最后得出的結果與真實的計算機所算的結果必須一致。
程序實現流程分析
從最簡單的開始。
1、按運算符的優先級別,先編寫一個程序實現對字符串的乘除處理
2、再編寫一個程序實現對字符串的加減處理
3、編寫一個程序實現對括號內容匹配處理
4、編寫對原始字符串數據的處理,甄別。是否輸入錯誤等。。。。
實現:
1、先實現乘除功能:
# -*- coding:utf-8 -*- import re ''' Created on 2018年7月10日 @author: Administrator ''' #第一步,實現一個公式的乘除 #9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 假設沒有空格在里面 sub_s='9-10.0/3 + 7/3*99/4*2998 +10*568/14 ' print(sub_s) #先計算乘除 def chengchu(gongshi): new_s_s=gongshi if '*' in new_s_s or '/' in new_s_s:#先計算乘除 sub_sub_s=re.search('(\d*\.?\d*)([*/])(\d*\.?\d*)',new_s_s) if sub_sub_s==None: pass else: # print(sub_sub_s) # print(sub_sub_s.span()) # print(sub_sub_s.group()) if sub_sub_s.group(2)=='*': sss=str(float(sub_sub_s.group(1))*float(sub_sub_s.group(3))) # print(sss) elif sub_sub_s.group(2)=='/': sss = str(float(sub_sub_s.group(1)) / float(sub_sub_s.group(3))) # print(sss) else: print('沒有需要運算的乘除法。') # s_new=s[0:18]+'-8'+s[25:] # gongshi[0:sub_sub_s.span()[0]] + sss + gongshi[sub_sub_s.span()[1]:] new_s_s=gongshi[0:sub_sub_s.span()[0]]+sss+gongshi[sub_sub_s.span()[1]:] # print(new_s_s) return chengchu(new_s_s) else: return new_s_s # if '+' in gongshi or '-' in gongshi: # 再計算加減 #再計算加減 def jiajian(): pass print(chengchu(sub_s))
運行結果:
"D:\Program Files (x86)\python36\python.exe" F:/python從入門到放棄/7.5/計算器.py 9-10.0/3 + 7/3*99/4*2998 +10*568/14 9-3.3333333333333335 + 173134.50000000003 +405.7142857142857 Process finished with exit code 0
2、實現加減功能:
1 #再計算加減 sub_s_s=9-3.3333333333333335 + 173134.50000000003 +405.7142857142857 2 sub_s_s='9-3.3333333333333335+173134.50000000003+405.7142857142857' #假設沒有空格 3 print(sub_s_s) 4 def jiajian(gongshi_jiajian): 5 new_s_s = gongshi_jiajian 6 if '+' in new_s_s or '-' in new_s_s:#計算加減 7 sub_sub_s=re.search('(\d*\.?\d*)([+-])(\d*\.?\d*)',new_s_s) 8 if sub_sub_s==None: 9 pass 10 else: 11 if sub_sub_s.group(2) == '+': 12 sss=str(float(sub_sub_s.group(1))+float(sub_sub_s.group(3))) 13 # print(sss) 14 elif sub_sub_s.group(2)=='-': 15 sss = str(float(sub_sub_s.group(1)) - float(sub_sub_s.group(3))) 16 # print(sss) 17 else: 18 print('沒有需要運算的加減法。') 19 new_s_s = sss + gongshi_jiajian[sub_sub_s.span()[1]:] 20 # print(new_s_s) 21 return jiajian(new_s_s) 22 else: 23 return new_s_s 24 25 print(jiajian(sub_s_s))
運行結果:
"D:\Program Files (x86)\python36\python.exe" F:/python從入門到放棄/7.5/計算器.py 9-3.3333333333333335+173134.50000000003+405.7142857142857 173545.88095238098 Process finished with exit code 0
3、實現匹配出最里層的括號內容
1 # -*- coding:utf-8 -*- 2 import re 3 ''' 4 Created on 2018年7月9日 5 6 @author: Administrator 7 ''' 8 #用戶輸入一個類似這樣 3*( 4+ 50 )-(( 100 + 40 )*5/2- 3*2* 2/4+9)*((( 3 + 4)-4)-4) 9 # 這樣的表達式,假設表達式里面除了包含空格、'+'、'-'、'*'、'/'和括號再無其他特殊符號 10 s='1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )' 11 s1='1 - 2 * ( (60-30* (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )' 12 def kuohao(gongshi_kuohao):#輸入帶括號的公式 13 str_kuohao=gongshi_kuohao 14 if '(' in str_kuohao and ')' in str_kuohao: 15 guize_kuohao = re.compile('(\()([^()]*)(\))') # 匹配出最里層的括號的規則 16 print(guize_kuohao.search(str_kuohao)) 17 print(guize_kuohao.search(str_kuohao).group()) 18 print(guize_kuohao.search(str_kuohao).group(1)) 19 print(guize_kuohao.search(str_kuohao).group(2))#取到最里層括號里面的字符串 20 print(guize_kuohao.search(str_kuohao).group(3)) 21 22 print(kuohao(s)) 23 print(kuohao(s1))
運行結果:
"D:\Program Files (x86)\python36\python.exe" F:/python從入門到放棄/7.5/計算器.py <_sre.SRE_Match object; span=(18, 25), match='(-40/5)'> (-40/5) ( -40/5 ) None <_sre.SRE_Match object; span=(18, 58), match='(9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )'> (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 ) ( 9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 ) None Process finished with exit code 0
4、實現原始字符串錯誤檢測,處理功能
1 # -*- coding:utf-8 -*- 2 import re 3 ''' 4 Created on 2018年7月9日 5 6 @author: Administrator 7 ''' 8 #用戶輸入一個類似這樣 3*( 4+ 50 )-(( 100 + 40 )*5/2- 3*2* 2/4+9)*((( 3 + 4)-4)-4) 9 # 這樣的表達式,假設表達式里面除了包含空格、'+'、'-'、'*'、'/'和括號再無其他特殊符號 10 s='1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2))' 11 def qingxi(gongshi_qingxi):##對原始公式進行清洗、 12 str_qingxi_kongge=re.sub('\s','',gongshi_qingxi)#去掉所有空格 13 # print(str_qingxi_kongge) 14 #統計括號 15 str_qingxi_kuohao=re.findall('[\(\)]',str_qingxi_kongge) 16 # print(str_qingxi_kuohao) 17 if str_qingxi_kuohao.count('(')==str_qingxi_kuohao.count(')'):#左括號和右括號相等 18 for i in range(1,int(len(str_qingxi_kuohao))):#判斷左側的左括號,要一直大於等於左側的右括號 19 # print(i) 20 if str_qingxi_kuohao[0:i].count('(') >= str_qingxi_kuohao[0:i].count(')'): 21 continue 22 else: 23 print('公式中括號出現錯誤,請檢查第 %d 括號問題'%i) 24 else: 25 print('公式中括號出現錯誤,括號不是成對出現。') 26 # if re.search('\([^\d]\)',str_qingxi_kongge): 27 # print('公式中括號出現錯誤,出現空括號') 28 29 return str_qingxi_kongge 30 31 print(qingxi(s))
結果:
"D:\Program Files (x86)\python36\python.exe" F:/python從入門到放棄/7.5/計算器.py 1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2)) Process finished with exit code 0
最終結果:(對於之前寫的代碼,存在邏輯上漏洞,也在下面代碼中改善)
1 # -*- coding:utf-8 -*- 2 import re 3 4 ###############################################清洗,格式化字符串######################################################################### 5 def qingxi(string):##對原始公式進行清洗、 6 flag=True 7 string=string.replace(' ','')#去掉所有空格 8 string = string.replace('+-', '-') 9 string = string.replace('--', '+') 10 string = string.replace('++', '+') 11 string = string.replace('-+', '-') 12 string = string.replace('*+', '*')#假設,只有加減乘除運算。輸入時可能出現,但是運算中不可能遇到這種情況 13 string = string.replace('/+', '/') #假設,只有加減乘除運算。輸入時可能出現,但是運算中不可能遇到這種情況 14 #防止出現 類似 2*-3==(-1)*2*3 15 s_str=re.search('(\d+\.?\d*\*)(-)', string) 16 if s_str : 17 s_str=s_str.group(1)#拿到-前面的數字 2* 18 string = re.sub('\d+\.?\d*\*-', '-'+s_str, string) # 防止出現 類似 2*-3==-2*3 19 s_str_sub = re.search('(\d+\.?\d*/)(-)', string) 20 if s_str_sub: 21 s_str = s_str_sub.group(1) # 拿到-前面的數字 2* 22 string = re.sub('\d+\.?\d*/-', '-' + s_str, string) # 防止出現 類似 2/-3==-2/3 23 24 # 遇到+- 或是-+ 統統換成- 運算符 25 str_qingxi=re.findall('[\(\)]',string) 26 if re.findall('[a-z]+',string.lower()): 27 print('存在非法字符',re.findall('[a-z]+',string.lower())) 28 flag=False 29 elif str_qingxi.count('(')==str_qingxi.count(')'):#左括號和右括號相等 ()必須成對出現 30 for i in range(1,int(len(str_qingxi))):#判斷左側的左括號,要一直大於等於左側的右括號,防止出現類似 ))(( 的情況 31 if str_qingxi[0:i].count('(') >= str_qingxi[0:i].count(')'): 32 continue 33 else: 34 print('公式中括號出現錯誤,請檢查第 %d 處括號問題'%i) 35 flag=False 36 else: 37 print('公式中括號出現錯誤,存在括號沒有閉合。') 38 if flag: 39 return string 40 ###############################################乘除計算######################################################################### 41 def chengchu(string): 42 43 44 if '*' in string or '/' in string:#先計算乘除 45 s_string = re.search('(\d+\.?\d*)([*/])(\d+\.?\d*)', string) 46 s_s_string=s_string.group()# 47 # s_string = re.search('(\d+\.?\d*)([*/])(\d+\.?\d*)', string) 48 # s_s_string = s_string.group() 49 # if s_string: 50 51 if s_string.group(2)=='*': 52 sss=str(float(s_string.group(1))*float(s_string.group(3))) 53 # print(sss) 54 new_string = string.replace(s_s_string, sss) 55 return chengchu(new_string) 56 elif s_string.group(2)=='/': 57 sss = str(float(s_string.group(1)) / float(s_string.group(3))) 58 # print(sss) 59 new_string = string.replace(s_s_string, sss) 60 return chengchu(new_string) #遞歸。。。 61 else: 62 # print('沒有需要運算的乘除法。') 63 return string 64 65 ###############################################加減計算######################################################################### 66 def jiajian(string): 67 s_string = re.search('(\d+\.?\d*)([+-])(\d+\.?\d*)', string) 68 if s_string:#條件成立,表示匹配到加法,或是加法公式。如果匹配'-5',則條件不成立,沒有返回值 69 s_s_string=s_string.group() 70 if s_string.group(2) == '+': 71 sss=str(float(s_string.group(1))+float(s_string.group(3))) 72 new_string=string.replace(s_s_string,sss) 73 return jiajian(new_string) 74 elif s_string.group(2)=='-': 75 sss =str(float(s_string.group(1)) - float(s_string.group(3))) 76 new_string=string.replace(s_s_string,sss) 77 return jiajian(new_string) 78 else: 79 # print('沒有需要運算的加減法。') 80 return string 81 ###############################################組合計算######################################################################### 82 def jisuanqi(string):#計算器函數 83 84 while re.search('\(',string):#有括號 85 string = qingxi(string)#每對最里層的括號運算一次,清洗一下,防止出現'--5',‘+-8’ 等情況 86 strs=re.search('\([^()]+\)',string).group()#檢測最里層的括號 87 # strs_s_s=strs.group() 88 strs_s=chengchu(strs)# 89 strs_s=qingxi(strs_s) 90 strs_s=jiajian(strs_s).strip('()')# 91 string=string.replace(strs,strs_s) 92 93 else:#無括號 94 string = qingxi(string)#每對最里層的括號運算一次,清洗一下,防止出現'--5',‘+-8’ 等情況 95 strs = chengchu(string) 96 strs=qingxi(strs) 97 strs = jiajian(strs) 98 return strs# 99 100 101 102 sour='1 + 2 * ((60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) +- (-4*3)/ (16-3*2))' 103 s1=jisuanqi(sour) 104 print(s1)
運行結果:
"D:\Program Files (x86)\python36\python.exe" F:/python從入門到放棄/計算器3.py -2776675.4952380955 Process finished with exit code 0