Implémenter une instance d'une calculatrice

PHP中文网
Libérer: 2017-06-20 14:35:47
original
1376 Les gens l'ont consulté

Tâche : Développement d'une calculatrice

  (1) Mise en œuvre de l'analyse des priorités d'addition, de soustraction, de multiplication, de division et d'extension

 (2) Entrée utilisateur1 - 2 * ( (60-30 +(-40/5) * (-9-2*5/-3 + 7/3*99/4 *2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) ) et d'autres formules similaires, vous devez analyser les symboles et formules (), +, -, *, / à l'intérieur. Après l'opération Pour obtenir un résultat, celui-ci doit être cohérent avec ce que produirait une vraie calculatrice.

Le code est le suivant :

 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)
Copier après la connexion

Processus d'exécution du programme :

Idée générale : Nous savons que pour calculer le format de la chaîne ci-dessus, vous peut utiliser la fonction eval(), mais ici nous devons écrire une calculatrice nous-mêmes ; nous savons que la priorité des opérations mathématiques est que les parenthèses ont la priorité la plus élevée, et les éléments entre parenthèses sont opérés en premier, donc notre idée est de faire correspondre les parenthèses dans la mémoire, puis effectuons l'opération, après avoir fait correspondre le contenu dans les parenthèses de mémoire, nous calculons, puis utilisons la valeur calculée pour remplacer la valeur à la position d'origine dans la chaîne jusqu'à ce qu'il n'y ait plus de position de parenthèse dans la chaîne. cette fois, nous suivons l’ordre normal des opérations pour effectuer les calculs.

1. Correspondance régulière, trouvez d'abord les parenthèses mémoire ; le code est le suivant :

formule = '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())

Les résultats en cours d'exécution sont les suivants :

(-9-2*5/-3 + 7 /3*99/4*2998 +10 * 568/14 )

Ci-dessus, nous avons observé la chaîne extraite de la mémoire. On peut voir qu'il y a de nombreux endroits qui doivent être modifiés. Il y a de nombreux espaces dans la chaîne, ce qui affectera. notre calcul. De plus, pendant le processus de calcul, nous n'avons pas besoin de parenthèses, alors supprimez-les également.

2. Supprimez les espaces et les crochets

formula_deep = re.sub("[() ]", "",formula_deep)

se déroule comme suit :

-9-2*5/-3+7 / 3*99/4*2998+10*568/14
3. Après avoir obtenu la chaîne ci-dessus, lorsque nous effectuons l'opération couche par couche, +-, -+, ++, --, etc. . Ceci doit également être traité. Puisqu'il s'agit maintenant du premier niveau, le problème ne peut pas être vu. Après l'opération, si la mémoire obtient un nombre négatif, alors s'il y a + ou - en dehors des parenthèses précédentes, il deviendra. +-, -, etc., ceci Même si cela ne fonctionne pas, il doit être traité

formula_deep = re.sub("+-",'-',formula_deep)
formula_deep = re.sub("-+",'-',formula_deep)
 formula_deep = re.sub("++" ,"+",formula_deep)
formula_deep = re.sub("--",'+',formula_deep)

Le fonctionnement est le suivant :

-9-2*5/-3+7/3*99/4*2998 +10*568/14

4. Lorsque le traitement ci-dessus est terminé, le calcul démarre officiellement. Nous savons que le calcul doit d'abord calculer la multiplication et la division, car la multiplication et la division ont le même effet. priorité la plus élevée, car la multiplication et la division doivent être trouvées en premier, et l'addition et la soustraction peuvent être calculées une fois le calcul terminé

calc_sign = re.findall("[+- ; ]",formula_deep)
calc_list = re.split("[+-]",formula_deep)
print(calc_list)
print(calc_sign)

fonctionne comme suit :

['', '9', '2*5/', '3', '7/3*99/4* 2998', '10*568/14']
 ['-', '-', '-', '+', '+']

Nous avons le liste de calcul et symboles d'opération, ['', '9', '2*5/', '3', '7/3*99/4*2998', '10*568/14']Il y a aussi des problèmes à l'intérieur. Tout d'abord, le premier élément de la liste est "" vide, ce qui signifie que cette situation ne se produit que lorsqu'elle est précédée d'un signe - et qu'il y en a 2. *5/ , cette description est également suivie d'un nombre négatif, qui doit être traité avant que le calcul du budget puisse être effectué. Pourquoi cela se produit-il ? En effet, pendant l'opération, nous utilisons "+" ou "-" pour diviser la chaîne. Cela fera que s'il s'agit d'un nombre négatif, elle sera divisée au début, le devant sera divisé par un vide, ceci. entraînera une erreur dans notre calcul car nous devons le modifier.

5. Modifiez l'opération ci-dessus :

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)
pour index, e in enumerate(calc_list):
 if e.endswith("/") ou e.endswith("*") :
'''Indique que ce qui suit est un nombre négatif et doit être corrigé'''
          calc_list[index+1] = calc_list[index] + calc_sign[index] + calc_list[index+1]
         del calc_list[index]
 del calc_sign[index]

print( "calc_list:",calc_list )
 print("calc_sign:",calc_sign)

Exécutez comme suit :

calc_list : ['- 9', '2*5/', '3', '7/3*99/4*2998', '10*568/14']
 calc_sign : ['-' , '-', '+', '+']
liste_calc : ['-9', '2*5/-3', '7/3*99/4*2998', '10*568/ 14']
calc_sign : ['-', '+', '+']

Comme vous pouvez le voir ci-dessus, nous avons effectué la correction en deux coups. la première fois nous avons supprimé l'espace "" au début du problème élémentaire ; la deuxième fois, le cas de la multiplication et de la division suivie de nombres négatifs est évoqué ;

    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)
Copier après la connexion

    运算结果如下:

    ['*', '/']
  ['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)
Copier après la connexion

    运行结果如下:

    ['-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)
Copier après la connexion

    运行如下:

    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>
Copier après la connexion

    上述代码中,体现了一个思想,由于我们想实现的是前一个数字加上后一个数字,但是没有直接的方法,这个时候,我们就可以先定义一个空值,然后对这个值进行判断,其实判断的目的就是为了给这个变量赋值,赋值就是列表的第一个元素,这样我们就能实现列表中元素每次循环都进行叠加或叠减。这个思想很好。当不存在,想让它存在的时候,就先定义一个空值进行判断,判断之后在进行赋值。赋值之后,相当于result等于元素的第一个值,并且元素下一次循环也是从第二个值开始,列表的长度索引也没有超标。

    2、正则表达式的利用,re(regular的缩写):

    ^表示非,"\"表示转义,就是让表示字符本身的含义,+代表一个或多个

    "\(.[^()]+\)"代表匹配括号,括号中间是包含任意多个不是()的元素,也就是匹配最内层的括号。

    3、字符串的replace()方法,就把字符串进行查找替换,str.replace(old,new),正则中字符串findall()查找元素中所有的正则表达式的值,放在一个列表中;re.split()字符串的分割,按照某个正则字符串进行分割。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal