利用正则制作计算器

核心思想:1.先考虑没有括号的式子如何进行运算,然后考虑正则匹配有括号的式子,通过逐步替换

利用正则计算:1 - 2 * ( (60-30 +(-40/5) * 20) - (-4*3)/ (16-3*2) )

# 方案1

#!/usr/bin/env python    # -*- coding:utf-8 -*-
# author: Learning       time:2018/4/30

import re
# 定义一个乘除运算函数,最终返回一个运算结果
def mul_div(cal):
    if '*' in cal:
        x, y = cal.split('*')
        return float(x) * float(y)
    if '/' in cal:
        x, y = cal.split('/')
        return float(x) / float(y)
    
# 定义一个处理加减符号的函数,这步是由于乘除运算完可能为负导致的
def proce_symbol(cal):
    cal = cal.replace('++','+')
    cal = cal.replace('+-', '-')
    cal = cal.replace('--', '+')
    cal = cal.replace('-+', '-')
    return cal

# 定义一个对内层没有括号的公式进行运算的函数,最终返回一个结果
def inner(content):
    """
    这步对内层的乘除进行循环处理,直到里面没有了乘除运算,全部替换成了结果
    :param content:
    :type content:
    :return: 一个不带括号的运算式的结果
    :rtype:
    """
    # 浮点型匹配整数和浮点数啊哥,不是整数匹配浮点数
    # 最后变成这样1-2*-128.8,要注意这里的正则匹配
    con = re.search(r'\d+\.?\d*[*/]\-?\d+\.?\d*', content)
    while con:  # 如果当中有乘除号
        con = con.group()
        temp = mul_div(con)  # 得到结果
        content = content.replace(con,str(temp))  # 对内层运算式进行替换
        content = proce_symbol(content)
        #替换计算式中的乘除运算,直到替换完,对于冲突的+-号也进行替换
        return inner(content)   # 通过循环一直运算式中的乘除运算计算完
    else:   # 如果没有乘除号
        # 对加减进行运算处理,把他们整到列表里面,挨个进行处理计算
        lis = re.findall(r'[+-]?\d+\.?\d*', content)
        if len(lis)>0:
            total_num = 0
            for i in lis:
                total_num += float(i)
            return total_num
        else:
            return lis[0]

# 匹配最内层的括号
def pars(cal):
    """
    定义一个计算最内层运算的函数
    :param cal:
    :type cal:
    :return:最能层运算
    :rtype:
    """
    par = re.search('\(([^()]*)\)', cal)
    while par:   # 如果当中有括号
        content = par.group()   # (-40/5)
        temp = inner(content.strip('()'))  # 去括号,并处理结果-8
        cal = cal.replace(content,str(temp))
        return pars(cal)
    # 判断里面的运算符,可以有加减乘除
    else:
        ret = inner(cal) # 如果没有括号
        return ret

a = input('计算式:').strip()
# 去除空格处理,得到1-2*((60-30+(-40/5)*20)-(-4*3)/(16-3*2))
a = re.sub('\s','', a)
print(pars(a))

 方案2:

import re
def cal(exp):
    if '*' in exp:
        a,b = exp.split('*')
        return str(float(a) * float(b))
    elif '/' in exp:
        a, b = exp.split('/')
        return str(float(a) / float(b))

def format(exp):
    exp = exp.replace('++',"+")
    exp = exp.replace('-+',"-")
    exp = exp.replace('+-',"-")
    exp = exp.replace('--',"+")
    return exp

def dealwith(no_bracket_exp):
    # 匹配乘除法
    while True:
        mul_div = re.search('\d+(\.?\d+)?[*/]-?\d+(\.?\d+)?', no_bracket_exp)
        if mul_div:
            exp = mul_div.group()
            result = cal(exp)
            no_bracket_exp = no_bracket_exp.replace(exp, result, 1)  # (-8)
        else:break
    no_bracket_exp = format(no_bracket_exp)
    # 计算加减法
    lst = re.findall(r'[-+]?\d+(?:\.\d+)?', no_bracket_exp)
    res = str(sum([float(i) for i in lst]))
    return res   # 返回一个计算完毕的字符串数据类型的 数字

def remove_bracket(s):
    s = s.replace(' ', '')     # 去掉空格
    while True:
        ret = re.search(r'\([^()]+\)', s)   # 匹配最内层的括号
        if ret:      # 能匹配到括号 就先处理括号内的加减乘除
            no_bracket_exp = ret.group()    # 拿到括号中的表达式
            ret = dealwith(no_bracket_exp)  # 把括号中的表达式交给的dealwith
            s = s.replace(no_bracket_exp, ret, 1)
        else:       # 不能匹配到括号 就字节处理加减乘除
            ret = dealwith(s)  # 把表达式交给的dealwith
            return ret

s = '1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )'
print(remove_bracket(s))

 和方案二一样:

a = '1 - 2 * ( (60-30 +(-40/5) * 20) - (-4*3)/ (16-3*2) )'
import re
new_a = re.sub(' ','',a)  # 去括号处理
def proce_symbol(cal):  # 去重复加减号
    if '++' in cal:cal = cal.replace('++','+')
    if '+-' in cal:cal = cal.replace('+-', '-')
    if '--' in cal:cal = cal.replace('--', '+')
    if '-+' in cal:cal = cal.replace('-+', '-')
    return cal
def mul_div(famula):
    if '*' in famula:
        num1, num2 = famula.split('*')
        total = str(float(num1) * float(num2))
        return total
    if '/' in famula:
        num1, num2 = famula.split('/')
        total = str(float(num1) / float(num2))
        return total
def total(famula):
    while True:
        if '*' or '/' in famula:
            num = re.search(r'\d+(\.?\d+)?[*/]\-?\d+(\.?\d+)?',famula)
            if num:
                num = num.group()
                nums = mul_div(num)
                famula = famula.replace(num, nums, 1)
                famula = proce_symbol(famula)
           # 如果算式中剩下加减运算
            else:
                lis = re.findall(r'[-]?\d+(?:\.?\d+)?',famula)
                sums = sum([float(i) for i in lis])
                return sums
def bras(famu):
    while True:
        bra = re.search('\([^()]+\)',famu)  # 获取括号内的内容
        if bra:
            bra = bra.group()
            ret = total(bra)
            famu = famu.replace(bra,str(ret),1)
            s = proce_symbol(famu)
            return bras(s)
        else:
            s = proce_symbol(famu)
            ret = total(s)
            return ret
print(bras(new_a))
  

  

  


posted @ 2018-05-08 16:05  -Learning-  阅读(327)  评论(0编辑  收藏  举报