zangyue

1.极限压缩版

import re, functools
def cal(formula):
    while re.search(\'(?:\d+\.?\d+|\d+)[+\-*/]\', formula):
        while re.search(\'[*/]\', formula): formula = re.sub(\'(?:\d+\.?\d+|\d+)[*/](?:\d+\.?\d+|\d+)\', str(functools.reduce(lambda i, j: float(i) * float(j), re.search(\'(?:\d+\.?\d+|\d+)[*/](?:\d+\.?\d+|\d+)\', formula).group().split(\'*\')) if \'*\' in re.search(\'(?:\d+\.?\d+|\d+)[*/](?:\d+\.?\d+|\d+)\', formula).group() else functools.reduce(lambda i, j: float(i) / float(j), re.search(\'(?:\d+\.?\d+|\d+)[*/](?:\d+\.?\d+|\d+)\', formula).group().split(\'/\'))), formula, 1)
        if re.search(\'(?:\d+\.?\d+|\d+)[+\-]\', formula): formula = re.sub(\'-?(?:\d+\.?\d+|\d+)[+\-](?:\d+\.?\d+|\d+)\', str(functools.reduce(lambda i, j: float(i) + float(j), re.search(\'-?(?:\d+\.?\d+|\d+)[+\-](?:\d+\.?\d+|\d+)\', formula).group().rsplit(\'+\', 1)) if \'+\' in re.search(\'(?:\d+\.?\d+|\d+)[+\-](?:\d+\.?\d+|\d+)\', formula).group() else functools.reduce(lambda i, j: float(i) - float(j), re.search(\'-?(?:\d+\.?\d+|\d+)[+\-](?:\d+\.?\d+|\d+)\', formula).group().rsplit(\'-\', 1))), formula, 1)
    return formula
formula = \'1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))\'
while re.search(\'\([^\(\)]+\)\', formula):
    formula = re.sub(\'\([^\(\)]+\)\', cal(re.search(\'\([^\(\)]+\)\', re.sub(\'\s\', \'\', formula)).group()).strip(\'()\'), formula, 1)
    while re.search(\'[+\-*/]-\', formula): formula = re.sub(\'[+]-\', \'-\', formula) if \'+-\' in formula else re.sub(\'--\', \'\', formula) if formula.startswith(\'--\') else re.sub(\'(?:\d+\.?\d+|\d+)[*/]-\', \'-\' + re.findall(\'(?:\d+\.?\d+|\d+)[*/](?=-)\', formula)[0], formula) if re.search(\'[*/]-\', formula) else re.sub(\'--\', \'+\', formula)
print(cal(formula).split(\'.0\')[0] if cal(formula).endswith(\'.0\') else cal(formula))

 

2.完整版

import re
from functools import reduce


def plus_minus(formula):
    \'\'\'
    计算无括号的加减法算式
    :param formula: 等待计算的只包含加减法的字符串
    :return: 计算结果的字符串
    \'\'\'
    p1 = re.compile(\'-?(?:\d+\.?\d+|\d+)[+\-](?:\d+\.?\d+|\d+)\')  # 匹配一次加减法
    while re.search(p1, formula):  # 每次计算一个二元加减,并替换到原字符串上,直到计算并计算完所有数
        x = re.search(p1, formula).group()  # 匹配出一次计算,判断是加法还是减法,再由reduce把分割后的两个数交给匿名函数去计算。
        formula = re.sub(p1, str(reduce(lambda i, j: float(i) + float(j), x.rsplit(\'+\', 1)) if \'+\' in x else reduce(lambda i, j: float(i) - float(j), x.rsplit(\'-\', 1))), formula, 1)
    return formula
    # ps.计算加减法可以采用与乘除法不同的方式,可以把所有数全匹配出来再一起计算出来


def multi_divi(formula):
    \'\'\'
    计算无括号的乘除法算式
    :param formula: 等待计算的只包含乘除法的字符串
    :return: 计算结果的字符串
    \'\'\'
    p = re.compile(\'(?:\d+\.?\d+|\d+)[*/](?:\d+\.?\d+|\d+)\')
    while re.search(p, formula):
        y = re.search(p, formula).group()
        formula = re.sub(p, str(reduce(lambda i, j: float(i) * float(j), y.split(\'*\')) if \'*\' in y else reduce(lambda i, j: float(i) / float(j), y.split(\'/\'))), formula, 1)
    return formula


def parentheses_parse(formula):
    \'\'\'
    用来处理括号,并调用加减乘除完成计算
    :param formula: 数学算式的字符串,支持加减乘除和括号
    :return: 最终结果的整型或浮点型
    \'\'\'
    formula = re.sub(\'\s\', \'\', formula)
    p = re.compile(\'\([^\(\)]+\)\')  # 匹配内层括号
    while re.search(p, formula):  # 循环到没有括号为止
        f = re.search(p, formula).group()
        formula = re.sub(p, plus_minus(multi_divi(f)).strip(\'()\'), formula, 1)  # 调用加减法嵌套乘除法,计算完括号内的式子,并去除括号

        # 处理去除括号后可能出现的其他符号与负号相连的情况
        while re.search(\'[+\-*/]-\', formula):
            formula = re.sub(\'[+]-\', \'-\', formula)
            formula = re.sub(\'--\', \'\', formula) if formula.startswith(\'--\') else re.sub(\'--\', \'+\', formula)  # 正负为负,负负为正,并且避免正号出现在最前端
            if re.search(\'[*/]-\', formula):  # 遇到乘除连接负号的情况时,需要先把负号前置,再进行一次上面加减连接负号的处理
                n = re.search(\'(?:\d+\.?\d+|\d+)[*/](?=-)\', formula).group()  # 这里使用正向预匹配获得如\'7*-\'这样的序列中的\'7*\'的部分
                formula = re.sub(\'(?:\d+\.?\d+|\d+)[*/]-\', \'-\' + n, formula)  # 使用刚获得的字符串进行替换,来使‘7*-’变成‘-7*’的样子
    formula = plus_minus(multi_divi(formula))  # 没有括号了,再计算最后一次
    if formula.endswith(\'.0\'):  # 优化显示
        formula = int(formula.split(\'.0\')[0])
    else:
        formula = float(formula)
    return formula


# 在此处输入算式
print(parentheses_parse(\'1-2*((60-  30+(-40/5)*(9  -2*5/3+7/3*99/4*2998+1  0*568/14))-(-4*3)/(16-3*2))\'))

 

3.思路清晰版

import re
from functools import reduce

def mul_div(exp):
    """
    计算两个数的乘法或者除法
    :param exp:
    :return:
    """
    if \'*\' in exp:
        a, b = exp.split(\'*\')
        return float(a)*float(b)
    if \'/\' in exp:
        a, b = exp.split(\'/\')
        return float(a) / float(b)

def exp_fmt(exp):
    """
    符号整理
    :param exp:
    :return:
    """
    while re.search(\'[+-]{2,}\',exp):
        exp = exp.replace(\'--\',\'+\')
        exp = exp.replace(\'+-\',\'-\')
        exp = exp.replace(\'-+\',\'-\')
        exp = exp.replace(\'++\',\'+\')
    return exp

def remove_addsub(exp):
    """
    计算两个数的加减法
    :param exp:
    :return:
    """
    ret = re.findall(\'[-+]?\d+(?:\.\d+)?\',exp)
    res = reduce(lambda a,b:float(a)+float(b),ret)
    return res

def remove_muldiv(exp):
    """
    计算表达式中的所有的乘除法
    :param exp:
    :return:
    """
    while True:
        ret = re.search(\'\d+(\.\d+)?[*/]-?\d+(\.\d+)?\',exp)
        if ret:
            son_exp = ret.group()
            res = mul_div(son_exp)
            exp = exp.replace(son_exp,str(res))
        else:return exp

def cal(exp):
    res = remove_muldiv(exp)            # 计算乘除
    res = exp_fmt(res)                  # 符号整理
    ret = remove_addsub(res)            # 计算加减
    return ret

def main(exp):
    exp = exp.replace(\' \',\'\')
    while True:
        ret = re.search(\'\([^()]+\)\', exp)
        if ret:
            res = cal(ret.group())
            exp = exp.replace(ret.group(), str(res))
        else: return cal(exp)
exp = \'1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )\'
ret = main(exp)
print(ret)

 

待续

分类:

技术点:

相关文章: