用正则表达式实验计算器功能

本文介绍怎样用正则表达式实现一个简单的计算器。(文章中的代码为Python3)

1.问题描述

用正则表达式实现一个简单计算器的功能:输入为一个字符串(含有加减乘除,正负和整数及浮点数的计算公式),输出为运算结果。

2.想要达到的效果

输入计算公式:1.2+-(2*4+(2+5))-3.4,结果为:-10.4。也就是说我们允许用户输入整数和小数,计算包括加减乘除,当然如果用户想要注明数的正负也是可以识别的。

3.解决思路

3.1明确优先级

(1)():小括号的优先级最高。括号的嵌套结构中,内部的括号的优先级高于外部的括号。
(2)*或/:乘除号的优先级低于小括号,但是高于加减。
(3)+或-:加减号的优先级最低。

3.2可能包含的函数

(1)用户输入函数:这个函数在程序启动的时运行:包括提示用户输入;获得用户输入;对用户的输入进行简单的合法性验证;将用户的输入转换成标准的模式。
(2)去括号:这个是按照优先级的顺序,首先去除表达式中的括号(括号中的字符用计算结果代替)。这个函数需要调用运算函数。
(3)去乘除:这个函数是按照优先级的顺序得到乘除运算的结果,并将结果带入计算的公式中。
(4)去加减:这个函数用于加减计算。
经过上面的各个函数,用户输入的计算公式将会得到唯一的运算结果。

具体代码如下所示(python3):

__author__ = "Allen Liu"
__time__ = "2017/7/29"
'''This program is used to calculate the result of the formula using re  '''
import re # 加载re模块
import sys # 加载sys模块用于结束程序
# 定义用户输入函数
def user_input():
    ''' 用户输入函数,包括提示信息并得到用户输入 '''
    print("Welcome use this calculator".center(50,'-'))# 输出欢迎语句
    input_formula = input("Please input your formula or input q to exit:")# 提示用户输入
    if input_formula.lower() == 'q':# 判断用户输入是否为q(退出程序)
        sys.exit('Looking forward to your re-use!')
    elif input_legal(input_formula) == False:# 简单的判断下输入是否合法
        sys.exit('Sorry, your input is illegal!')
    else:
        normal_formula = input_normal(input_formula)
    print(normal_formula)
    return normal_formula

# 判断用户的输入是否合法,合法的时候返回True,否则返回False
def input_legal(input_formula):
    ''' 判断用户输入是否有其他非法字符,有则返回False,否则为True '''
    indicator = re.search(r'[^(0123456789\.\+\-\*\/\(\)\s)]',input_formula)
    if indicator == None:
        indicator = True
    else:
        indicator = False
    return indicator

# 规范化用户的输入,去掉空格和不必要的正负号
def input_normal(input_formula):
    ''' 将用户输入变成比较规范的格式 '''
    iput = re.sub('\s*', '', input_formula)  # 去除空格
    input_formula = input_formula.replace('+-', '-')  # 替换表达式里的所有'+-'
    input_formula = input_formula.replace('--', '+')  # 替换表达式里的所有'--'
    input_formula = input_formula.replace('-+', '-')  # 替换表达式里的所有'-+'
    input_formula = input_formula.replace('++', '+')  # 替换表达式里的所有'++'
    return input_formula

# 去括号函数
def del_bra(expression):
    ''' 递归的去除括号,输入为含有括号的表达式,输出为去括号后的表达式 '''
    if not re.search(r'\(([^()]+)\)', expression):  # 判断小括号,如果不存在小括号,直接调用乘除,加减计算
        ret1 = mul_div(expression)
        ret2 = add_min(ret1)
        return ret2  # 返回最终计算结果
    data = re.search(r'\(([^()]+)\)', expression).group()  # 如果有小括号,匹配出优先级最高的小括号
    # print("获取表达式",data)
    data = data.strip('[\(\)]')  # 剔除小括号
    ret1 = mul_div(data)  # 计算乘除
    # print("全部乘除计算完后的表达式:",ret1)
    ret2 = add_min(ret1)  # 计算加减
    # print("全部加减计算结果:",ret2)
    part1, replace_str, part2 = re.split(r'\(([^()]+)\)', expression, 1)  # 将小括号计算结果替换回表达式
    expression = '%s%s%s' % (part1, ret2, part2)  # 生成新的表达式
    return del_bra(expression)  # 递归去小括号

# 定义乘除运算函数
def mul_div(expression):
    ''' 去除乘除运算,返回没有乘除运算的表达式。输入为去括号后的只含有加减乘除运算的表达式,输出为只含有加减运算的表达式 '''
    val = re.search('\d+\.*\d*[\*\/]+[\+\-]?\d+\.*\d*', expression)  # 匹配乘除号
    if not val:  # 乘除号不存在,返回输入的表达式
        return expression
    data = re.search('\d+\.*\d*[\*\/]+[\+\-]?\d+\.*\d*', expression).group()  # 匹配乘除号
    if len(data.split('*')) > 1:  # 当可以用乘号分割,证明有乘法运算
        part1, part2 = data.split('*')  # 以乘号作为分割符
        value = float(part1) * float(part2)  # 计算乘法
    else:
        part1, part2 = data.split('/')  # 用除号分割
        if float(part2) == 0:  # 如果分母为0,则退出计算
            sys.exit("Sorry,the divisor equals zero!")
        value = float(part1) / float(part2)  # 计算除法
    # 获取第一个匹配到的乘除计算结果value,将value放回原表达式
    s1, s2 = re.split('\d+\.*\d*[\*\/]+[\+\-]?\d+\.*\d*', expression, 1)  # 分割表达式
    # print("上一个表达式:",expression)
    next_expression = "%s%s%s" % (s1, value, s2)  # 将计算结果替换会表达式
    # print("下一个表达式%s" % next_expression)
    return mul_div(next_expression)  # 递归表达式

# 定义加减函数,用于表达式中的加减计算
def add_min(expression):
    '''计算公式中的加减运算,输入为只含有加减运算的公式,输出为运算结果'''
    # 格式化表达式,因为这时候可能还还有正负号
    expression = expression.replace('+-', '-')  # 替换表达式里的所有'+-'
    expression = expression.replace('--', '+')  # 替换表达式里的所有'--'
    expression = expression.replace('-+', '-')  # 替换表达式里的所有'-+'
    expression = expression.replace('++', '+')  # 替换表达式里的所有'++'
    data = re.search('\d+\.*\d*[\+\-]{1}\d+\.*\d*', expression)  # 匹配加减号
    if not data:  # 如果不存在加减号,则证明表达式已计算完成,返回最终结果
        return expression
    val = re.search('[\-]?\d+\.*\d*[\+\-]{1}\d+\.*\d*', expression).group()
    if len(val.split('+')) > 1:  # 以加号分割成功,有加法计算
        part1, part2 = val.split('+')
        value = float(part1) + float(part2)  # 计算加法
    elif val.startswith('-'):  # 如果是已'-'开头则需要单独计算
        part1, part2, part3 = val.split('-')
        value = -float(part2) - float(part3)  # 计算以负数开头的减法
    else:
        part1, part2 = val.split('-')
        value = float(part1) - float(part2)  # 计算减法
    s1, s2 = re.split('[\-]?\d+\.*\d*[\+\-]{1}\d+\.*\d*', expression, 1)  # 分割表达式
    # print("计算%s=%s" % (val,value))
    next_expression = "%s%s%s" % (s1, value, s2)  # 将计算后的结果替换回表达式,生成下一个表达式
    # print("下一个表达式: ",next_expression)
    return add_min(next_expression)  # 递归运算表达式

# 主函数
if __name__ == "__main__":
    '''将计算结果与eval()函数的结果进行比较,来确定计算的正确性'''
    try:
        expression = user_input()  # 获取用户输入的表达式
        reslut = eval(expression)  # 用eval计算验证
        ret = del_bra(expression)  # 用函数计算后得出的结果
        reslut = float(reslut)
        ret = float(ret)
        if reslut == ret:  # 将两种方式计算的结果进行比较,如果相等,则计算正确,输出结果
            print("eval计算结果:%s" % reslut)
            print("表达式计算结果:%s" % ret)
        else:  # 两种计算方式的结果不正确,提示异常,并返回两种方式的计算结果
            print("计算结果异常,请重新检查!")
            print("eval计算结果:%s" % reslut)
            print("表达式计算结果:%s" % ret)
    except(SyntaxError, ValueError, TypeError):  # 如果有不合法输出,则抛出错误
        print("输入表达式不合法,请重新检查!")



  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值