宿題: 電卓の開発
1 - 2 * ( (60-30 +(-40) /5) * (-9-2 ※5 /-3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) ) など。数式の後に、() を解析する必要があります。 +、-、*、/ の記号と数式を自分で入力し、演算後の結果を実際の電卓で得た結果と一致させる必要があります。
コードは次のとおりです:
1 import re 2 3 formula = '1 - 2 * ( (60-30 +(-9-2*5/-3 + 7 /3*99/4*2998 +10 * 568/14 ) * (-40/5)) - (-4*3)/ (16-3*2) )' 4 #formula = "(1++1)" 5 def modify(formula_deep): 6 '''程序修饰函数,去除空格和括号''' 7 '''去除运算中出现的+- -- ++ -+ 等情形''' 8 formula_deep = re.sub("[() ]","",formula_deep) #替换空格和空号 9 formula_deep = re.sub("\+-","-",formula_deep) #替换+-为-10 formula_deep = re.sub("--",'+',formula_deep) #替换--为+11 formula_deep = re.sub("-\+",'-',formula_deep)12 formula_deep = re.sub("\++","+",formula_deep)13 return formula_deep14 15 def multiply_divide(formula_deep):16 '''计算乘除'''17 '''由于乘除是首先计算的,我们的思路是,首先计算乘除,然后把计算的结果替换进去,就可以得到只剩加减的情形'''18 calc_sign = re.findall("[+-]",formula_deep) #提取字符串中所有的加减号19 calc_list = re.split("[+-]",formula_deep) #以加减号进行分割,得到乘除20 '''由于我们得到的calc_list:['', '9', '2*5/', '3', '7/3*99/4*2998', '10*568/14'],里面由于-号引起的麻烦,-9被分割了,2*5/等'''21 if calc_list[0] == '':22 '''处理列表开头“”空的情况,说明这里是负数,被我们分割掉了要重新进行合并'''23 calc_list[1] = calc_sign[0] + calc_list[1]24 del calc_sign[0]25 del calc_list[0]26 for num,line in enumerate(calc_list):27 '''处理2*5/的情形,说明这种后面除的是一个负数,因为只有负数才会出现这种情况2*5/-3被分割了,需要合并'''28 if line.endswith("/") or line.endswith("*"):29 '''如果结尾包括乘除号,说明是负数被拆分了'''30 calc_list[num+1] = calc_list[num] + calc_sign[num] + calc_list[num+1]31 del calc_sign[num]32 del calc_list[num]33 '''下面进行乘除的正式运算,上面都是进行格式转换'''34 for index,string in enumerate(calc_list):35 '''首先提取编号,便于后面替换运算出来的值'''36 if "/" in string or "*" in string:37 mul_div_sign = re.findall("[/*]",string)38 mul_div_list = re.split("[/*]",string)39 calc_value = None40 for e_index,e in enumerate(mul_div_list):41 if calc_value:42 if mul_div_sign[e_index-1] == "/":43 calc_value /= float(e)44 elif mul_div_sign[e_index-1] == "*":45 calc_value *= float(e)46 else:47 calc_value = float(e)48 calc_list[index] = calc_value49 else:50 pass51 '''计算值'''52 value = None53 for k,v in enumerate(calc_list):54 '''计算加减的情况'''55 if value:56 if calc_sign[k-1] == "-":57 value -= float(v)58 elif calc_sign[k-1] == '+':59 value += float(v)60 else:61 value = float(v)62 return value63 64 65 def main(formula):66 '''程序主入口,生成带括号的情况'''67 while True:68 formula_deep = re.search("\(.[^()]+\)",formula)69 if formula_deep:70 formula_deep = formula_deep.group()71 formula_list = modify(formula_deep)72 '''得到修整好要计算的字符串,现在开始进行计算-9-2*5/-3+7/3*99/4*2998+10*568/14'''73 calc_value = multiply_divide(formula_list)74 formula = formula.replace(formula_deep,str(calc_value))75 else:76 '''处理不带括号的情形'''77 formula = modify(formula)78 calc_last_value = multiply_divide(formula)79 print("formula:",calc_last_value)80 exit()81 82 if __name__=="__main__":83 main(formula)
プログラム実行プロセス:
一般的な考え方: 上記の文字列の形式を計算するには eval() 関数を使用できることはわかっていますが、ここでは自分で計算機を作成する必要があります。数学的演算の優先順位は、括弧内のものが最初に計算されることです。したがって、メモリの括弧内の内容を一致させてから、演算を実行するという考えです。次に、文字列内に括弧の位置がなくなるまで、値が文字列内の元の位置の値を置き換えます。このとき、通常の演算順序に従って計算を実行します。
1. 通常のマッチングでは、まずメモリ括弧を見つけます。コードは次のとおりです:
式 = '1 - 2 * ( ( (60-30 +(-9-2*5/-) 3 + 7 /3* 99/4*2998 +10 * 568/14 ) * (-40/5)) - (-4*3)/ (16-3*2) )'
formula_deep = re.search( "(.[^()]+)",formula)
print(formula_deep.group())
実行結果は以下の通りです。 ( -9-2*5 /-3 + 7 /3*99/4*2998 +10 * 568/14 )
上記のメモリから抽出された文字列を観察しました。変更する必要がある場所がたくさんあることを示します。文字列にはスペースが多くあり、計算に影響します。また、計算中に括弧は必要ないため、括弧を削除する必要があります。 2. スペースと括弧を削除します。
Formula_deep = re.sub("[() ]",
"",formula_deep)
次のように実行します。 - 9 -2*5/-3+7/3*99/4*2998+10*568/14 3. 上記の文字列を取得した後、レイヤーごとに操作を実行すると、+-、-+、+ が可能になります。 +、- などの状況もこの時点で処理する必要があります。これは、操作後に取得されたメモリが負の数である場合、+ または - がある場合に問題が発生することがわかりません。前の括弧の外側では + -、- になり、その他の状況は現時点では不可能であり、対処する必要があります Formula_deep = re.sub("+-",
'-',formula_deep; )formula_deep = re.sub(" -+",'-',formula_deep)
formula_deep = re.sub("++","+",formula_deep)
formula_deep = re.sub(" --",
次のように実行します:
-9-2*5/-3+7/3*99/4*2998+10* 568/14 4. 上記の場合、処理が完了すると、計算は最初に乗算と除算を計算する必要があることがわかります。これは、乗算と除算が最も優先されるためです。乗算と除算を見つける必要があるためです。計算が完了したら加算と減算を計算できます。 calc_sign = re.findall( "[+-]",formula_deep) calc_list = re.split("[+-]",formula_deep) print(calc_list)
print(calc_sign)
次のように実行します:
['', '9', '2*5/', '3', '7/3*99/4*2998', '10*568/14']
[ '-', '-', '-', '+', '+']
計算のリストと演算記号 ['', '9', '2*5 を取得しました。 /' , '3', '7/3*99/4*2998', '10*568/14'] まず、リストの最初の要素が空です。この状況は - 数値でのみ発生することを示します。この状況はマージする必要があり、この説明の後には負の数値も続き、事前計画の計算を行う前に最初に処理する必要があります。なぜこのような状況が起こるのでしょうか?これは、操作中に文字列を分割するために「+」または「-」を使用するためです。これにより、負の数の場合、先頭が 1 つの空で分割されます。計算を変更する必要があるため、計算にエラーが発生します。
5. 上記の操作を変更します:
if calc_list[0] == "":
calc_list[1] = calc_sign[0] + calc_list[1]
del calc_list[0]
del calc_sign[0]
print("calc_list:",calc_list)
print("calc_sign:",calc_sign)
for Index,e enumerate(cal c_list ): L1] = CALC_LIST [インデックス] + Calc_sign [インデックス] + Calc_list [インデックス +
1]
Del Calc_sign [Ind ex]
"Calc_list:", C alc_list) r proprint ( "calc_sign:",calc_sign)
次のように実行されます: calc_list: ['-9', '2*5/', '3', '7/3*99/4*2998', '10*568/14'] calc_sign: ['-', '-', '+', '+'] calc_list: ['-9', '2*5/-3', '7/3*99/4*2998', '10*568/14'] calc_sign: ['-', '+', '+']
上記からわかるように、最初の「」空要素の問題を削除するのは 2 つのステップです。 ; 2 回目は、負の数が続く乗算と除算の場合を提案します。
6、这个时候,我们就要进行计算了,我们首先遍历calc_list: ['-9', '2*5/-3', '7/3*99/4*2998', '10*568/14']中的元素,因为我们要先进行乘除,因此找到包含"/"或"*"的字符串,进行求值,然后进行替换,就可以得到没有乘除的字符串,只包含加减情况:
for num,value in enumerate(calc_list):if "/" in value or "*" in value:"""说明包含乘除,首先进行计算"""mul_div_sign = re.findall("[/*]",value) mul_div_list = re.split("[*/]",value) print(mul_div_sign) print(mul_div_list)
运算结果如下:
['*', '/']
['2', '5', '-3']
['/', '*', '/', '*']
['7', '3', '99', '4', '2998']
['*', '/']
['10', '568', '14']
我们得到了运算符和里面的数字,现在只要判断乘除号,然后就可以利用前面一个乘以后面一个进行计算了。如下:
7、乘除计算:
1 for num,value in enumerate(calc_list): 2 if "/" in value or "*" in value: 3 """说明包含乘除,首先进行计算""" 4 mul_div_sign = re.findall("[/*]",value) 5 mul_div_list = re.split("[*/]",value) 6 '''接下来,我们计算乘除的情况,首先我们要遍历乘除,因为要进行元素递乘''' 7 res = None 8 for e_index,e_value in enumerate(mul_div_list): 9 if res:10 if mul_div_sign[e_index-1] == "/":11 res /= float(e_value)12 elif mul_div_sign[e_index-1] == "*":13 res *= float(e_value)14 else:15 res = float(e_value) #如果不存在,就生成一个新的,但是我们定义的是不存在的情况,因此肯定是先生成一个数,然后在进行计算16 calc_list[num] = res17 else:18 pass19 20 print(calc_list)21 print(calc_sign)
运行结果如下:
['-9', -3.3333333333333335, 173134.50000000003, 405.7142857142857]
['-', '+', '+']
上述代码,我们进行了乘除的运算,让运算里面不在存在乘除,只需要进行加减运算即可。
可以看见,我们运算之后,只剩下了加减,这样,我们就可以利用列表的元素和符号进行加减运算。
8、加减运算:
1 '''进行加减运算''' 2 result = None 3 for k_index,k_value in enumerate(calc_list): 4 if result: 5 if calc_sign[k_index-1] == "+": 6 result += float(k_value) 7 elif calc_sign[k_index-1] == '-': 8 result -= float(k_value) 9 else:10 result = float(k_value)11 print("result:",result)
运行如下:
result: 173534.54761904766
9、上面,我们得到了运算的结果,然后只需要替换内存括号的内容即可,这样一层一层替换,最终只会剩下没有括号的运算,这个时候,我们在这行这个函数,就能得到最终的结果。
知识点:
(1):
<span style="font-family: 宋体; font-size: 16px">result = <span style="color: #000080">None<br></span><span style="color: #000080">for </span><span style="background-color: #ffe4ff">k_index</span>,k_value <span style="color: #000080">in </span><span style="color: #000080">enumerate</span>(calc_list):</span><br><span style="font-family: 宋体; font-size: 16px"> <span style="color: #000080">if </span>result:</span><br><span style="font-family: 宋体; font-size: 16px"> <span style="color: #000080">if </span>calc_sign[<span style="background-color: #e4e4ff">k_index</span>-<span style="color: #0000ff">1</span>] == <span style="color: #008080">"+"</span>:</span><br><span style="font-family: 宋体; font-size: 16px"> result += <span style="color: #000080">float</span>(k_value)</span><br><span style="font-family: 宋体; font-size: 16px"> <span style="color: #000080">elif </span>calc_sign[<span style="background-color: #e4e4ff">k_index</span>-<span style="color: #0000ff">1</span>] == <span style="color: #008080">'-'</span>:</span><br><span style="font-family: 宋体; font-size: 16px"> result -= <span style="color: #000080">float</span>(k_value)</span><br><span style="font-family: 宋体; font-size: 16px"> <span style="color: #000080">else</span>:</span><br><span style="font-family: 宋体; font-size: 16px"> result = <span style="color: #000080">float</span>(k_value)</span>
上述代码中,体现了一个思想,由于我们想实现的是前一个数字加上后一个数字,但是没有直接的方法,这个时候,我们就可以先定义一个空值,然后对这个值进行判断,其实判断的目的就是为了给这个变量赋值,赋值就是列表的第一个元素,这样我们就能实现列表中元素每次循环都进行叠加或叠减。这个思想很好。当不存在,想让它存在的时候,就先定义一个空值进行判断,判断之后在进行赋值。赋值之后,相当于result等于元素的第一个值,并且元素下一次循环也是从第二个值开始,列表的长度索引也没有超标。
2、正则表达式的利用,re(regular的缩写):
^表示非,"\"表示转义,就是让表示字符本身的含义,+代表一个或多个
"\(.[^()]+\)"代表匹配括号,括号中间是包含任意多个不是()的元素,也就是匹配最内层的括号。
3、字符串的replace()方法,就把字符串进行查找替换,str.replace(old,new),正则中字符串findall()查找元素中所有的正则表达式的值,放在一个列表中;re.split()字符串的分割,按照某个正则字符串进行分割。
以上が電卓のインスタンスを実装するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。