当前位置: 首页
AI教程
Python计算器模拟eval表达式求值完整代码实现解析

Python计算器模拟eval表达式求值完整代码实现解析

热心网友 时间:2026-06-16
转载

实现了一个模拟Python内置eval函数的计算器,能够处理带括号和加减乘除的算术表达式。核心流程包括:用正则表达式将表达式拆分为列表;通过递归和计数器逐层剥离最内层括号,并处理符号粘连问题;无括号后先计算乘除再计算加减,最终返回浮点数结果。

先来谈谈这个项目的初衷:目标是实现一个类似于Python内置eval函数的功能,能够处理包含括号、加减乘除的复杂算术表达式,从而提供一个简洁的计算器工具。当然,这里不涉及安全性和性能的考虑,纯粹是为了练习递归算法和数据处理技巧。

整体思路非常清晰,核心可以分为三个步骤:首先,利用正则表达式将原始字符串拆分成列表,方便逐项处理——将数字、运算符和括号分别提取出来。其次,采用递归方式逐步去除最内层的括号,一层层向外剥离,直到整个表达式不再包含括号。这一步需要妥善处理符号粘连的问题,例如- - -等情况。最后,在没有括号的表达式上,先进行乘除运算,再进行加减运算,最终得到计算结果。

关键难点在于括号的剥离方式。不能简单使用index()来查找左括号,因为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)

_
参考链接:
link

来源:https://developer.aliyun.com/article/704739

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
AI如何从聊天能力进化到做事能力 Skill的实践之路

AI如何从聊天能力进化到做事能力 Skill的实践之路

让AI从“会聊天”转向“会做事”的关键在于Skill(技能包)。Skill由可执行代码、精确的说明书(如JSONSchema描述)及结果翻译器构成。通过精细定义参数与边界,AI能稳定调用接口完成重启服务、查询数据等操作,从而从空谈顾问变为可靠的数字员工。

时间:2026-07-10 11:09
零基础看懂Agent Skill MCP三层关系解读

零基础看懂Agent Skill MCP三层关系解读

智能体是自主执行任务的实体,技能是被封装的原子能力,MCP协议是智能体与技能间的标准化通信协议。智能体通过MCP协议发现并调用技能,灵活组合完成复杂任务。三者解耦,实现即插即用,降低了系统集成复杂度。

时间:2026-07-10 11:09
AI编码时代UI自动化测试智能化演进之路—中国平安人寿蔡雪

AI编码时代UI自动化测试智能化演进之路—中国平安人寿蔡雪

AI编码时代,UI自动化测试面临效率断层。平安人寿蔡雪基于自研“女娲”平台,分享从可视化录制到AI智能录制、基于EventDOM的智能感知与自愈机制的演进路径,实现用例创建降本、维护减负、执行提稳,推动测试工具从自动化向智能化升级。

时间:2026-07-10 11:09
一文讲清Agent、Skill、MCP到底什么关系:零基础小白三层拆解

一文讲清Agent、Skill、MCP到底什么关系:零基础小白三层拆解

Agent是自主执行任务的数字打工人,Skill为原子化能力函数,MCP是标准协议接口。Agent通过MCP发现并调用Skill,实现即插即用,解耦技能与智能体,让大模型能力安全、统一、可扩展地集成。

时间:2026-07-10 11:09
文生图同一提示词为何每次不同?随机性与可复现解析

文生图同一提示词为何每次不同?随机性与可复现解析

文生图每次结果不同源于从随机噪声开始去噪。固定种子(seed)可锁定初始噪声,但还需采样步数、引导强度、采样器、尺寸、提示词、模型等参数一致才能复现。通过控制变量法调参,先固定种子再逐一调整其他参数,可精确归因差异。

时间:2026-07-10 11:09
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 热门数据榜