作业:计算器开发

  (1)实现加减乘除及拓号优先级解析;

  (2)用户输入 1 - 2 * ( (60-30 +(-40/5) * (-9-2*5/-3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等类似公式后,必须自己解析里面的(),+,-,*,/符号和公式,运算后得出结果,结果必须与真实的计算器所得出的结果一致。

代码如下:

 import re

 formula = '1 - 2 * ( (60-30 +(-9-2*5/-3 + 7 /3*99/4*2998 +10 * 568/14 ) * (-40/5)) - (-4*3)/ (16-3*2) )'
#formula = "(1++1)"
def modify(formula_deep):
'''程序修饰函数,去除空格和括号'''
'''去除运算中出现的+- -- ++ -+ 等情形'''
formula_deep = re.sub("[() ]","",formula_deep) #替换空格和空号
formula_deep = re.sub("\+-","-",formula_deep) #替换+-为-
formula_deep = re.sub("--",'+',formula_deep) #替换--为+
formula_deep = re.sub("-\+",'-',formula_deep)
formula_deep = re.sub("\++","+",formula_deep)
return formula_deep def multiply_divide(formula_deep):
'''计算乘除'''
'''由于乘除是首先计算的,我们的思路是,首先计算乘除,然后把计算的结果替换进去,就可以得到只剩加减的情形'''
calc_sign = re.findall("[+-]",formula_deep) #提取字符串中所有的加减号
calc_list = re.split("[+-]",formula_deep) #以加减号进行分割,得到乘除
'''由于我们得到的calc_list:['', '', '*/', '', '/*/*', '*/'],里面由于-号引起的麻烦,-9被分割了,2*5/等'''
if calc_list[] == '':
'''处理列表开头“”空的情况,说明这里是负数,被我们分割掉了要重新进行合并'''
calc_list[] = calc_sign[] + calc_list[]
del calc_sign[]
del calc_list[]
for num,line in enumerate(calc_list):
'''处理2*5/的情形,说明这种后面除的是一个负数,因为只有负数才会出现这种情况2*5/-3被分割了,需要合并'''
if line.endswith("/") or line.endswith("*"):
'''如果结尾包括乘除号,说明是负数被拆分了'''
calc_list[num+] = calc_list[num] + calc_sign[num] + calc_list[num+]
del calc_sign[num]
del calc_list[num]
'''下面进行乘除的正式运算,上面都是进行格式转换'''
for index,string in enumerate(calc_list):
'''首先提取编号,便于后面替换运算出来的值'''
if "/" in string or "*" in string:
mul_div_sign = re.findall("[/*]",string)
mul_div_list = re.split("[/*]",string)
calc_value = None
for e_index,e in enumerate(mul_div_list):
if calc_value:
if mul_div_sign[e_index-] == "/":
calc_value /= float(e)
elif mul_div_sign[e_index-] == "*":
calc_value *= float(e)
else:
calc_value = float(e)
calc_list[index] = calc_value
else:
pass
'''计算值'''
value = None
for k,v in enumerate(calc_list):
'''计算加减的情况'''
if value:
if calc_sign[k-] == "-":
value -= float(v)
elif calc_sign[k-] == '+':
value += float(v)
else:
value = float(v)
return value def main(formula):
'''程序主入口,生成带括号的情况'''
while True:
formula_deep = re.search("\(.[^()]+\)",formula)
if formula_deep:
formula_deep = formula_deep.group()
formula_list = modify(formula_deep)
'''得到修整好要计算的字符串,现在开始进行计算-9-2*5/-3+7/3*99/4*2998+10*568/14'''
calc_value = multiply_divide(formula_list)
formula = formula.replace(formula_deep,str(calc_value))
else:
'''处理不带括号的情形'''
formula = modify(formula)
calc_last_value = multiply_divide(formula)
print("formula:",calc_last_value)
exit() if __name__=="__main__":
main(formula)

    程序运行过程:

  大致思路:我们知道,要计算上面字符串的格式,可以使用eval()函数,但是这里我们要自己编写一个计算器;我们知道,数学运算的优先级是括号的优先级最高,先运算括号内的东西,因此我们的思路是匹配出内存的括号,然后进行运算,当把内存括号中的内容匹配出来之后,我们计算,然后用计算出来的值替换字符串中原来位置的值,一直替换到字符串中没有括号位置,这个时候我们就按照正常的运算顺序来进行计算。

1、正则匹配,先找到内存括号;代码如下:

formula = '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("--",'+',formula_deep)
    运行如下:

-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']里面也是有问题的,首先,列表的第一个元素是""空的情形,说明前面是-号才会有这种情况出现,这样的情况是要合并的,还有2*5/,这种说明后面跟着的也是负数,也要先进行处理才能进行预案算,为什么会出现这种情况呢?这是由于在运算的过程中,我们是以"+"或"-"来分割字符串的,这样就会造成如果是一个负数,就会被分割掉,在开头的时候,前面会被分割一个空,这样就会造成我们运算出错,因为要进行修改。

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 in enumerate(calc_list):
  if e.endswith("/") or e.endswith("*"):
  '''说明后面跟着的是负数,要进行修正'''
  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)

运行如下:

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: ['-', '+', '+']

从上面可以看出,我们分两笔进行了修正,第一次去除了开头的""空元素问题;第二次提出了乘除后面跟着负数的情况;

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、乘除计算:

 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)
'''接下来,我们计算乘除的情况,首先我们要遍历乘除,因为要进行元素递乘'''
res = None
for e_index,e_value in enumerate(mul_div_list):
if res:
if mul_div_sign[e_index-] == "/":
res /= float(e_value)
elif mul_div_sign[e_index-] == "*":
res *= float(e_value)
else:
res = float(e_value) #如果不存在,就生成一个新的,但是我们定义的是不存在的情况,因此肯定是先生成一个数,然后在进行计算
calc_list[num] = res
else:
pass print(calc_list)
print(calc_sign)

运行结果如下:

['-9', -3.3333333333333335, 173134.50000000003, 405.7142857142857]
  ['-', '+', '+']

上述代码,我们进行了乘除的运算,让运算里面不在存在乘除,只需要进行加减运算即可。

可以看见,我们运算之后,只剩下了加减,这样,我们就可以利用列表的元素和符号进行加减运算。

8、加减运算:

 '''进行加减运算'''
result = None
for k_index,k_value in enumerate(calc_list):
if result:
if calc_sign[k_index-] == "+":
result += float(k_value)
elif calc_sign[k_index-] == '-':
result -= float(k_value)
else:
result = float(k_value)
print("result:",result)

运行如下:

result: 173534.54761904766

9、上面,我们得到了运算的结果,然后只需要替换内存括号的内容即可,这样一层一层替换,最终只会剩下没有括号的运算,这个时候,我们在这行这个函数,就能得到最终的结果。

知识点:

(1):

result = None
for k_index,k_value in enumerate(calc_list):
if result:
if calc_sign[k_index-] == "+":
result += float(k_value)
elif calc_sign[k_index-] == '-':
result -= float(k_value)
else:
result = float(k_value)

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

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

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

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

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

day4 计算器的更多相关文章

  1. python作业day4计算器

    思路: 用循环提取最里面的括号,再进行运算 运算时利用正则表达式寻找相应的运算符 先进行乘除,再进行加减 (参考武sir和金角大王的代码) 流程图: 代码: #!/usr/bin/env python ...

  2. day4 作业计算器

    作业:计算器开发 (1)实现加减乘除及拓号优先级解析: (2)用户输入 1 - 2 * ( (60-30 +(-40/5) * (-9-2*5/-3 + 7 /3*99/4*2998 +10 * 56 ...

  3. python基础: day4作业计算器

    作业:计算器开发 实现加减乘除及拓号优先级解析 用户输入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - ...

  4. python2.0 s12 day4

    python2.0 s12 day404 python s12 day4 TengLan回顾上节内容 05 python s12 day4 迭代器原理及使用 本节大纲介绍: 1.迭代器&生成器 ...

  5. 1.C#WinForm基础制作简单计算器

    利用c#语言编写简单计算器: 核心知识点: MessageBox.Show(Convert.ToString(comboBox1.SelectedIndex));//下拉序号 MessageBox.S ...

  6. 自己动手写计算器v1.1

    这个改动主要是使用工厂模式替代了简单工厂模式,这样做的好处是如果以后我们要扩充其他运算时,就不用总是去修改工厂类, 这是可以采取工厂模式,主要是将原来简单工厂类的逻辑判断分离出来,将它作为一个借口,与 ...

  7. 自己动手写计算器v1.0

    今天突发奇想,想着看了还几个设计模式了,倒不如写点东西来实践它们.发现计算器这种就比较合适,打算随着设计模式的学习,会对计算器不断的做改进. 包括功能的增加和算法的改进.初学者难免犯错,希望大家不吝指 ...

  8. 【IOS开发笔记03-视图相关】简单计算器的实现

    UIView 经过前几天的快速学习,我们初步了解的IOS开发的一些知识,中间因为拉的太急,忽略了很多基础知识点,这些知识点单独拿出来学习太过枯燥,我们在今后的项目中再逐步补齐,今天我们来学习APP视图 ...

  9. [LeetCode] Basic Calculator 基本计算器

    Implement a basic calculator to evaluate a simple expression string. The expression string may conta ...

随机推荐

  1. Hadoop基础-HDFS递归列出文件系统-FileStatus与listFiles两种方法

    Hadoop基础-HDFS递归列出文件系统-FileStatus与listFiles两种方法 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. fs.listFiles方法,返回Loc ...

  2. 《剑指offer》 面试题53 :正则表达式匹配 Java

    引言:这道题情况比较复杂,边界条件较多,为了便于以后复习,整理一下.另外,由于C语言和Java对于字符串的操作存在不一样的地方,代码也存在改动. 题目:请实现一个函数用来匹配包含'.'和'*'的正则表 ...

  3. vue相关安装命令

    安装cnpm npm install cnpm -g --registry=https://registry.npm.taobao.org

  4. bzoj千题计划155:bzoj3543: [ONTAK2010]Garden

    http://www.lydsy.com/JudgeOnline/problem.php?id=3543 枚举每一个点,作为左下角 然后枚举 相同的x坐标,y坐标 少的那个 作为另一个角 二分判断另外 ...

  5. puppeteer截图

    puppeteer是谷歌官方出品的一个通过 DevTools 协议控制 headless Chrome 的Node库.可以通过Puppeteer的提供的api直接控制Chrome模拟大部分用户操作来进 ...

  6. iframe中的历史记录问题汇总及解决方案[转]

    在做页面统计的时候遇到了两个问题: 1.包含iframe的页面,在IE下按后退按钮不能刷新主页面.隐藏Iframe的src是统计程序的url,每点一次后退,就会发出一次页面加载时间请求. 2.由js动 ...

  7. [NOIP2015提高&洛谷P2678]跳石头 题解(二分答案)

    [NOIP2015提高&洛谷P2678]跳石头 Description 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和终点之 ...

  8. 【leetcode 简单】 第七十五题 第一个错误的版本

    你是产品经理,目前正在带领一个团队开发新的产品.不幸的是,你的产品的最新版本没有通过质量检测.由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的. 假设你有 n 个版本 [1, ...

  9. 用threading和Queue模块实现多线程的端口扫描器

    一.Queue模块基础 q = Queue.Queue()    q.qsize()           返回队列的大小  q.empty()         如果队列为空,返回True,反之Fals ...

  10. HDU 1242 Rescue (广搜)

    题目链接 Problem Description Angel was caught by the MOLIGPY! He was put in prison by Moligpy. The priso ...