20181221 2019-2020-2 《Python程序设计》实验二报告

课程:《Python程序设计》
班级: 1812
姓名: zyt
学号:20181221
实验教师:王志强
实验日期:2020年4月12日
必修/选修: 公选课

1.实验内容

  • 设计并完成一个完整的应用程序,完成加减乘除模等运算,功能多多益善。
  • 考核基本语法、判定语句、循环语句、逻辑运算等知识点

2. 实验过程及结果

实验中调用了python的re库,具体学习内容参考 Python标准库中的re模块

实验中用到了re的以下几种函数

1、re.sub(pattern,  repl,  string['',  count,  flags])

sub  (repl,  string['' , count=0])

说明:在字符串  string  中找到匹配正则表达式  pattern  的所有子串,用另一个字符串  repl  进行替换。如果没有找到匹配  pattern  的串,则返回未被修改的  string。repl  既可以是字符串也可以是一个函数。

2、re.split(pattern, string[, maxsplit=0, flags=0])

split  (string[,  maxsplit=0])
作用:可以将字符串匹配正则表达式的部分割开并返回一个列表

3、re.search(pattern,  string[,  flags])

search  (string[,  pos[,  endpos]])
作用:在字符串中查找匹配正则表达式模式的位置,返回  MatchObject  的实例,如果没有找到匹配的位置,则返回  None。

此外,还用到了一些基础的数组操作函数

1、list.pop([index=-1])

pop() 函数用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值。

2、list.append(obj)

append() 方法用于在列表末尾添加新的对象。

设计思路

这次的计算器设计让我想起了上个学期学习数据结构的时候,通过使用堆栈对中序表达式进行处理,得到运算结果。首先将计算式处理成列表,解决了'-'这个符号的判断问题。下面放出代码:
def formula_format(formula):
    formula = re.sub(' ', '', formula) # 去掉表达式式中的空格
    formula_list = [i for i in re.split('(\-\d+\.?\d*)', formula) if i] # 以 '-' + '数字' 分割表达式
    final_formula = [] # 创建最终的表达式列表
    for item in formula_list:
        if len(final_formula) == 0 and re.search('^\-\d+\.?\d*$', item): # 判断第一个是以横杠开头的数字是不是负数。
            final_formula.append(item)
        elif len(final_formula) > 0:
            if re.search('[\+\-\*\/\(]$', final_formula[-1]): # 判断表达式列表中最后一个是不是运算符号
                final_formula.append(item) 
            else: #分割表达式并写入表达式列表
                item_split = [i for i in re.split('([\+\-\*\/\(\)])', item) if i]
                final_formula += item_split
        else: #分割表达式并写入表达式列表
            item_split = [i for i in re.split('([\+\-\*\/\(\)])', item) if i]
            final_formula += item_split
    return final_formula #返回最终的表达式列表

接下来就是进行堆栈处理运算符的操作了

def decision(tail, now): #tail是栈顶元素,now是当前元素
    # 定义4种运算符优先度
    rank1 = ['+', '-']
    rank2 = ['*', '/']
    rank3 = ['(']
    rank4 = [')']
    if tail in rank1:
        if now in rank2 or now in rank3:  # 说明连续两个运算优先级不一样,需要入栈
            return -1
        else:
            return 1
    elif tail in rank2:
        if now in rank3:
            return -1
        else:
            return 1
    elif tail in rank3:
        if now in rank4:
            return 0  # 如果'(' 遇上 ')' 需要出栈 '('
        else:
            return -1  # 只要栈顶元素为'(',当前元素不是')',都应入栈。
    else:
        return -1
def final_calc(formula_list):
    num = []  # 定义数字栈
    operators = []  # 定义运算符栈
    for x in formula_list:
        operator = is_operator(x) # 调用函数判断,具体函数比较简单不详细介绍,在下面会给出
        if not operator: # 判断是否为运算符,否则压入数字栈
            num.append(float(x)) # 将字符串转换为浮点数进行运算,防止数值类型在运算中出现错误
        else: # 运算符处理
            while True:
                if len(operators) == 0: # 如果运算符栈等于0无条件入栈
                    operators.append(x)
                    break
                tag = decision(operators[-1], x) # 调用 decision 函数判断运算符优先级
                if tag == -1:
                    operators.append(x)  # 如果是-1压入运算符栈进入下一次循环
                    break
                elif tag == 0:
                    operators.pop() # 如果是0弹出运算符栈内最后一个'(', 丢掉当前')',进入下一次循环
                    break
                elif tag == 1:
                    op = operators.pop()  # 如果是1弹出运算符栈内最后两个元素,弹出数字栈最后两位元素。
                    num2 = num.pop()
                    num1 = num.pop()
                    num.append(calculate(num1, num2, op)) # 将运算之后的结果压入数字栈中
    while len(operators) != 0: # 判断是否还有未处理的元素
        op = operators.pop()
        num2 = num.pop()
        num1 = num.pop()
        num.append(calculate(num1, num2, op))
    return num , operators

接下来就是一些比较简单的判断函数、运算函数和主函数,不一一赘述

def is_operator(operator): #判断是否为运算符
    operators = ['+', '-', '*', '/', '(', ')']
    if operator in operators:
        return True
    else:
        return False

def calculate(n1, n2, operator): #对参数进行运算
    result = 0
    if operator == "+":
        result = n1 + n2
    if operator == "-":
        result = n1 - n2
    if operator == "*":
        result = n1 * n2
    if operator == "/":
        result = n1 / n2
    return result

x=1 #主函数,写了一个循环
while(x):
    try:
        print("请输入您的计算式")
        formula = input()
        formula_list = formula_format(formula)
        result ,_= final_calc(formula_list)
        print("计算结果:", result[0])
        x=int(input("是否继续运算? Yes for 1 / No for 0\n"))
    except ValueError:
        print("请正确输入计算式")
print("谢谢使用,再见!")

下面是实验运行结果:

请输入您的计算式
no
请正确输入计算式
请输入您的计算式
1-2*(1+1-6/2)
计算结果: 3.0
是否继续运算? Yes for 1 / No for 0
0
谢谢使用,再见!

3. 实验过程中遇到的问题和解决过程

  • 问题1:如何处理表达式的运算符号
  • 问题1解决方案:百度之后发现可以通过调用python自带的re库,re库具有许多好用的函数。
  • 问题2:如何判断'-'是代表减法运算还是负数
  • 问题2解决方案:也是通过百度,翻了许多相关的博客,最终得到启发,通过判断表达式'-'前一个是运算符号还是数字来判断。

其他(感悟、思考等)

有事不会问百度,百度上具有丰富的资源和信息。同时,dalao们写的各种博客也具有大量的参考价值。有时候可能看一个看不懂,但是多看几个不同的博客,有了不同的思路之后,解决问题就会相对容易起来,十分感谢愿意分享思路和方法的dalao们。说来说去,终究还是自己Python编程能力不够强,还是要有更多的学习。完整代码我已经上传到[码云](https://gitee.com/python_programming/zengyutao20181221/blob/master/%E8%AE%A1%E7%AE%97%E5%99%A8.py)