鱼C论坛

 找回密码
 立即注册
查看: 2196|回复: 27

[已解决]编写一个函数parse,实现计算器功能

[复制链接]
发表于 2020-5-30 13:55:57 | 显示全部楼层 |阅读模式
60鱼币
本帖最后由 Stubborn 于 2020-5-30 16:27 编辑

编写一个函数parse,实现计算器功能,仅支持   + - * / () ,整数。 如果表达式不正确,引发一个异常(不要使用内建函数直接返回答案,例如eval()  )
实例

  1. parse('1+2')
  2. >>>3
  3. parse('1+2*3')
  4. >>>7
  5. parse('1+2*(1+3)')
  6. >>>9
  7. parse('1+9/3')
  8. >>>4
复制代码



游客,如果您要查看本帖隐藏内容请回复
最佳答案
2020-5-30 13:55:58
本帖最后由 xiaosi4081 于 2020-6-1 18:04 编辑
  1. import re
  2. class suan:
  3.     def calculate(self,n1, n2, operator):

  4.         '''
  5.         :param n1: float
  6.         :param n2: float
  7.         :param operator: + - * /
  8.         :return: float
  9.         '''
  10.         result = 0
  11.         if operator == "+":
  12.             result = n1 + n2
  13.         if operator == "-":
  14.             result = n1 - n2
  15.         if operator == "*":
  16.             result = n1 * n2
  17.         if operator == "/":
  18.             result = n1 / n2
  19.         return result


  20.     # 判断是否是运算符,如果是返回True
  21.     def is_operator(self,e):
  22.         '''
  23.         :param e: str
  24.         :return: bool
  25.         '''
  26.         opers = ['+', '-', '*', '/', '(', ')']
  27.         return True if e in opers else False


  28.     # 将算式处理成列表,解决横杠是负数还是减号的问题
  29.     def formula_format(self,formula):
  30.         # 去掉算式中的空格
  31.         formula = re.sub(' ', '', formula)
  32.         # 以 '横杠数字' 分割, 其中正则表达式:(\-\d+\.?\d*) 括号内:
  33.         # \- 表示匹配横杠开头; \d+ 表示匹配数字1次或多次;\.?表示匹配小数点0次或1次;\d*表示匹配数字1次或多次。
  34.         formula_list = [i for i in re.split('(\-\d+\.?\d*)', formula) if i]

  35.         # 最终的算式列表
  36.         final_formula = []
  37.         for item in formula_list:
  38.             # 第一个是以横杠开头的数字(包括小数)final_formula。即第一个是负数,横杠就不是减号
  39.             if len(final_formula) == 0 and re.search('^\-\d+\.?\d*', item):
  40.                 final_formula.append(item)
  41.                 continue

  42.             if len(final_formula) > 0:
  43.                 # 如果final_formal最后一个元素是运算符['+', '-', '*', '/', '('], 则横杠数字不是负数
  44.                 if re.search('[\+\-\*\/\(], final_formula[-1]'):
  45.                     final_formula.append(item)
  46.                     continue
  47.             # 按照运算符分割开
  48.             item_split = [i for i in re.split('([\+\-\*\/\(\)])', item) if i]
  49.             final_formula += item_split
  50.         return final_formula


  51.     def decision(self,tail_op, now_op):
  52.         '''
  53.         :param tail_op: 运算符栈的最后一个运算符
  54.         :param now_op: 从算式列表取出的当前运算符
  55.         :return: 1 代表弹栈运算,0 代表弹运算符栈最后一个元素, -1 表示入栈
  56.         '''
  57.         # 定义4种运算符级别
  58.         rate1 = ['+', '-']
  59.         rate2 = ['*', '/']
  60.         rate3 = ['(']
  61.         rate4 = [')']

  62.         if tail_op in rate1:
  63.             if now_op in rate2 or now_op in rate3:
  64.                 # 说明连续两个运算优先级不一样,需要入栈
  65.                 return -1
  66.             else:
  67.                 return 1

  68.         elif tail_op in rate2:
  69.             if now_op in rate3:
  70.                 return -1
  71.             else:
  72.                 return 1

  73.         elif tail_op in rate3:
  74.             if now_op in rate4:
  75.                 return 0   # ( 遇上 ) 需要弹出 (,丢掉 )
  76.             else:
  77.                 return -1  # 只要栈顶元素为(,当前元素不是)都应入栈。
  78.         else:
  79.             return -1


  80.     def final_calc(self,formula_list):
  81.         num_stack = []       # 数字栈
  82.         op_stack = []        # 运算符栈
  83.         for e in formula_list:
  84.             operator = self.is_operator(e)
  85.             if not operator:
  86.                 # 压入数字栈
  87.                 # 字符串转换为符点数
  88.                 num_stack.append(float(e))
  89.             else:
  90.                 # 如果是运算符
  91.                 while True:
  92.                     # 如果运算符栈等于0无条件入栈
  93.                     if len(op_stack) == 0:
  94.                         op_stack.append(e)
  95.                         break

  96.                     # decision 函数做决策
  97.                     tag = decision(op_stack[-1], e)
  98.                     if tag == -1:
  99.                         # 如果是-1压入运算符栈进入下一次循环
  100.                         op_stack.append(e)
  101.                         break
  102.                     elif tag == 0:
  103.                         # 如果是0弹出运算符栈内最后一个(, 丢掉当前),进入下一次循环
  104.                         op_stack.pop()
  105.                         break
  106.                     elif tag == 1:
  107.                         # 如果是1弹出运算符栈内最后两个元素,弹出数字栈最后两位元素。
  108.                         op = op_stack.pop()
  109.                         num2 = num_stack.pop()
  110.                         num1 = num_stack.pop()
  111.                         # 执行计算
  112.                         # 计算之后压入数字栈
  113.                         num_stack.append(self.calculate(num1, num2, op))
  114.         # 处理大循环结束后 数字栈和运算符栈中可能还有元素 的情况
  115.         while len(op_stack) != 0:
  116.             op = op_stack.pop()
  117.             num2 = num_stack.pop()
  118.             num1 = num_stack.pop()
  119.             num_stack.append(self.calculate(num1, num2, op))

  120.         return num_stack, op_stack

  121.     def pause(self,formula):
  122.         formula_list = self.formula_format(formula)
  123.         result, _ = self.final_calc(formula_list)
  124.         print(result[0])
  125. try:
  126.     p = suan()
  127.     formula = input()
  128.     p.pause(formula)
  129. except:
  130.     print(formula)
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-5-30 13:55:58 | 显示全部楼层    本楼为最佳答案   
本帖最后由 xiaosi4081 于 2020-6-1 18:04 编辑
  1. import re
  2. class suan:
  3.     def calculate(self,n1, n2, operator):

  4.         '''
  5.         :param n1: float
  6.         :param n2: float
  7.         :param operator: + - * /
  8.         :return: float
  9.         '''
  10.         result = 0
  11.         if operator == "+":
  12.             result = n1 + n2
  13.         if operator == "-":
  14.             result = n1 - n2
  15.         if operator == "*":
  16.             result = n1 * n2
  17.         if operator == "/":
  18.             result = n1 / n2
  19.         return result


  20.     # 判断是否是运算符,如果是返回True
  21.     def is_operator(self,e):
  22.         '''
  23.         :param e: str
  24.         :return: bool
  25.         '''
  26.         opers = ['+', '-', '*', '/', '(', ')']
  27.         return True if e in opers else False


  28.     # 将算式处理成列表,解决横杠是负数还是减号的问题
  29.     def formula_format(self,formula):
  30.         # 去掉算式中的空格
  31.         formula = re.sub(' ', '', formula)
  32.         # 以 '横杠数字' 分割, 其中正则表达式:(\-\d+\.?\d*) 括号内:
  33.         # \- 表示匹配横杠开头; \d+ 表示匹配数字1次或多次;\.?表示匹配小数点0次或1次;\d*表示匹配数字1次或多次。
  34.         formula_list = [i for i in re.split('(\-\d+\.?\d*)', formula) if i]

  35.         # 最终的算式列表
  36.         final_formula = []
  37.         for item in formula_list:
  38.             # 第一个是以横杠开头的数字(包括小数)final_formula。即第一个是负数,横杠就不是减号
  39.             if len(final_formula) == 0 and re.search('^\-\d+\.?\d*', item):
  40.                 final_formula.append(item)
  41.                 continue

  42.             if len(final_formula) > 0:
  43.                 # 如果final_formal最后一个元素是运算符['+', '-', '*', '/', '('], 则横杠数字不是负数
  44.                 if re.search('[\+\-\*\/\(], final_formula[-1]'):
  45.                     final_formula.append(item)
  46.                     continue
  47.             # 按照运算符分割开
  48.             item_split = [i for i in re.split('([\+\-\*\/\(\)])', item) if i]
  49.             final_formula += item_split
  50.         return final_formula


  51.     def decision(self,tail_op, now_op):
  52.         '''
  53.         :param tail_op: 运算符栈的最后一个运算符
  54.         :param now_op: 从算式列表取出的当前运算符
  55.         :return: 1 代表弹栈运算,0 代表弹运算符栈最后一个元素, -1 表示入栈
  56.         '''
  57.         # 定义4种运算符级别
  58.         rate1 = ['+', '-']
  59.         rate2 = ['*', '/']
  60.         rate3 = ['(']
  61.         rate4 = [')']

  62.         if tail_op in rate1:
  63.             if now_op in rate2 or now_op in rate3:
  64.                 # 说明连续两个运算优先级不一样,需要入栈
  65.                 return -1
  66.             else:
  67.                 return 1

  68.         elif tail_op in rate2:
  69.             if now_op in rate3:
  70.                 return -1
  71.             else:
  72.                 return 1

  73.         elif tail_op in rate3:
  74.             if now_op in rate4:
  75.                 return 0   # ( 遇上 ) 需要弹出 (,丢掉 )
  76.             else:
  77.                 return -1  # 只要栈顶元素为(,当前元素不是)都应入栈。
  78.         else:
  79.             return -1


  80.     def final_calc(self,formula_list):
  81.         num_stack = []       # 数字栈
  82.         op_stack = []        # 运算符栈
  83.         for e in formula_list:
  84.             operator = self.is_operator(e)
  85.             if not operator:
  86.                 # 压入数字栈
  87.                 # 字符串转换为符点数
  88.                 num_stack.append(float(e))
  89.             else:
  90.                 # 如果是运算符
  91.                 while True:
  92.                     # 如果运算符栈等于0无条件入栈
  93.                     if len(op_stack) == 0:
  94.                         op_stack.append(e)
  95.                         break

  96.                     # decision 函数做决策
  97.                     tag = decision(op_stack[-1], e)
  98.                     if tag == -1:
  99.                         # 如果是-1压入运算符栈进入下一次循环
  100.                         op_stack.append(e)
  101.                         break
  102.                     elif tag == 0:
  103.                         # 如果是0弹出运算符栈内最后一个(, 丢掉当前),进入下一次循环
  104.                         op_stack.pop()
  105.                         break
  106.                     elif tag == 1:
  107.                         # 如果是1弹出运算符栈内最后两个元素,弹出数字栈最后两位元素。
  108.                         op = op_stack.pop()
  109.                         num2 = num_stack.pop()
  110.                         num1 = num_stack.pop()
  111.                         # 执行计算
  112.                         # 计算之后压入数字栈
  113.                         num_stack.append(self.calculate(num1, num2, op))
  114.         # 处理大循环结束后 数字栈和运算符栈中可能还有元素 的情况
  115.         while len(op_stack) != 0:
  116.             op = op_stack.pop()
  117.             num2 = num_stack.pop()
  118.             num1 = num_stack.pop()
  119.             num_stack.append(self.calculate(num1, num2, op))

  120.         return num_stack, op_stack

  121.     def pause(self,formula):
  122.         formula_list = self.formula_format(formula)
  123.         result, _ = self.final_calc(formula_list)
  124.         print(result[0])
  125. try:
  126.     p = suan()
  127.     formula = input()
  128.     p.pause(formula)
  129. except:
  130.     print(formula)
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-5-30 14:49:17 | 显示全部楼层
给出一个作弊答案:
  1. parse=eval
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-5-30 15:31:16 | 显示全部楼层
这不可能实现的,函数的参数必须指定,两个数且不是字符串用逗号隔开才行
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-5-30 15:34:44 | 显示全部楼层
这样我能帮你实现
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-5-30 15:39:05 | 显示全部楼层
这样我能帮你实现
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-5-30 15:42:36 | 显示全部楼层
给你链接给你百度一下百度一下https://www.cnblogs.com/zingp/p/8666214.html
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-5-30 15:55:27 | 显示全部楼层
Cool_Breeze 发表于 2020-5-30 15:42
给你链接给你百度一下百度一下https://www.cnblogs.com/zingp/p/8666214.html

我是过运行你给的文件,但是没有输入
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-5-30 15:57:23 | 显示全部楼层
liaoyiqin 发表于 2020-5-30 15:55
我是过运行你给的文件,但是没有输入

这个不是我的,大佬写的!
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-5-30 16:00:56 | 显示全部楼层
liaoyiqin 发表于 2020-5-30 15:31
这不可能实现的,函数的参数必须指定,两个数且不是字符串用逗号隔开才行

需要我贴代码出来吗,功能是可以实现的
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-5-30 16:01:37 | 显示全部楼层
Cool_Breeze 发表于 2020-5-30 15:57
这个不是我的,大佬写的!

嗯嗯,这个计算器的操作数是不能随意选择的
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-5-30 16:09:15 | 显示全部楼层
Stubborn 发表于 2020-5-30 16:00
需要我贴代码出来吗,功能是可以实现的

好的
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-5-30 16:29:22 | 显示全部楼层

在隐藏里面了
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-5-30 16:50:19 | 显示全部楼层
干嘛隐藏
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-5-30 16:57:23 | 显示全部楼层
参观大佬的代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-5-30 17:02:32 | 显示全部楼层


这样就没意思了呀,晚上我还想写写看呢,虽然很大概率写不出来
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-5-30 17:08:24 | 显示全部楼层
liaoyiqin 发表于 2020-5-30 15:31
这不可能实现的,函数的参数必须指定,两个数且不是字符串用逗号隔开才行


不要自己不会就说不可能。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-5-30 17:46:01 | 显示全部楼层
Twilight6 发表于 2020-5-30 17:02
这样就没意思了呀,晚上我还想写写看呢,虽然很大概率写不出来

不要看答案吗,写起来才有意思
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-5-30 20:30:44 | 显示全部楼层
答案
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-5-30 22:06:28 | 显示全部楼层
看看
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-30 18:16

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表