Python计算器模拟eval深度对比评测

2026-06-16阅读 0热度 0
Python

本项目旨在模拟 Python 内置 eval 函数的核心功能——解析包含括号、加减乘除的复杂算术表达式,打造一个轻量级计算器。不涉及安全性与性能优化,仅作为递归思维与数据处理的实战演练。

实现逻辑分为三个明确阶段:
1. 将原始字符串拆解为列表,便于逐项操作——借助正则表达式分离数字、运算符及括号。
2. 递归剥离最内层括号,逐层外扩直至表达式无括号。需处理负号粘连问题,例如 - - - 等边界情况。
3. 无括号后,优先计算乘除,再处理加减,输出最终数值。

括号剥离是核心难点。直接使用 index() 无法定位当前括号对,因为它始终返回第一个左括号。因此需自行维护一个计数器 count:遍历列表时遇到左括号记录其索引,直至遇到第一个右括号,切片取出中间子表达式,计算后替换原列表中对应片段。每次替换后递归调用,直至括号完全消除。

替换后极易产生 -- - 等冗余符号,因此专门设计 change() 函数:遇到连续两个减号则合并为加号(正负抵消),同时处理空格加负号等情况。该函数在递归及乘除运算后均需调用。

乘除运算同样采用递归:从左向右扫描列表,遇到 */ 时立即计算相邻两数,用结果替换左操作数,删除运算符和右操作数,然后递归调用自身,直至无乘除符号。需注意当右操作数为负数(如 * -)时,需特殊处理符号。

加减运算较为直观:遍历列表累加,但需留意首元素可能为负号。最终根据结果正负返回不同格式列表:正数返回字符串形式,负数返回 ['-', str(-sum)]

整体流程由 calculate() 函数根据表达式中是否存在乘除或加减符号自动调度对应处理模块,simplify() 函数负责递归剥离括号,而 calculator() 主函数依次完成字符串格式化、括号清除、计算并返回浮点结果。

完整代码实现如下,请留意正则拆分细节与符号边界处理:

import re

def eq_format(eq):
    '''
    将算术字符串拆分为列表,例如 '1-2*3' -> ['1','-','2','*','3']
    '''
    format_list = re.findall(r'[\d.]+|[()+\-*/]', eq)
    return format_list

def change(eq, count):
    '''
    处理列表中连续出现的 '-', '- -' 等符号问题
    比如 ['-', '-', '2'] -> ['+', '2']
    '''
    if eq[count] == '-':
        if eq[count-1] == '-':
            eq[count-1] = '+'
            del eq[count]
        elif eq[count-1] == '+':
            eq[count-1] = '-'
            del eq[count]
    return eq

def deal_multiplication_division(eq):
    '''
    递归处理所有乘除运算
    '''
    count = 0
    while count < len(eq):
        if eq[count] == '*':
            if eq[count+1] != '-':
                eq[count-1] = float(eq[count-1]) * float(eq[count+1])
                del eq[count]
                del eq[count]
            else:
                eq[count] = float(eq[count-1]) * float(eq[count+2])
                eq[count-1] = '-'
                del eq[count+1]
                del eq[count+1]
                eq = change(eq, count-1)
            return deal_multiplication_division(eq)
        elif eq[count] == '/':
            if eq[count+1] != '-':
                eq[count-1] = float(eq[count-1]) / float(eq[count+1])
                del eq[count]
                del eq[count]
            else:
                eq[count] = float(eq[count-1]) / float(eq[count+2])
                eq[count-1] = '-'
                del eq[count+1]
                del eq[count+1]
                eq = change(eq, count-1)
            return deal_multiplication_division(eq)
        count += 1
    return eq

def deal_plus_minus(eq):
    '''
    处理加减运算,返回最终结果的列表形式
    '''
    if eq[0] != '-':
        total = float(eq[0])
    else:
        total = 0.0
    count = 0
    for i in eq:
        if i == '-':
            total -= float(eq[count+1])
        elif i == '+':
            total += float(eq[count+1])
        count += 1
    if total >= 0:
        return [str(total)]
    else:
        return ['-', str(-total)]

def calculate(s_eq):
    '''
    不带括号的列表,先乘除后加减
    '''
    if '*' in s_eq or '/' in s_eq:
        s_eq = deal_multiplication_division(s_eq)
    if '+' in s_eq or '-' in s_eq:
        s_eq = deal_plus_minus(s_eq)
    return s_eq

def simplify(format_list):
    '''
    递归去除所有括号
    '''
    bracket = 0
    count = 0
    while count < len(format_list):
        if format_list[count] == '(':
            bracket = count
        elif format_list[count] == ')':
            temp = format_list[bracket+1 : count]
            new_temp = calculate(temp)
            format_list = format_list[:bracket] + new_temp + format_list[count+1:]
            format_list = change(format_list, bracket)
            return simplify(format_list)
        count += 1
    return format_list

def calculator(eq):
    format_list = eq_format(eq)
    s_eq = simplify(format_list)
    ans = calculate(s_eq)
    if len(ans) == 2:
        return -float(ans[1])
    else:
        return float(ans[0])

if __name__ == '__main__':
    equation = '1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'
    ans = calculator(equation)
    print('eval运算结果:', eval(equation))
    print('程序运算结果:', ans)

_
参考链接:
参考资源

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策