用正则表达式开发一个计算器,计算用户给定的一串带有加减乘除的公式。

要求:不能使用eval转换字符串

分析:

要求简单,就是计算混合运算,但是不能使用eval直接转换,主要就是把整个式子中的小括号优先匹配到进行计算再把计算结果替换到式子中,然后再根据小括号计算,直到没有小括号再按照加减乘除优先级计算,最后计算出结果。每次计算前把加减乘除符号格式化一下,比如有+和-同时存在的时候

代码发布区:github

#!usr/bin/env python
#-*- coding:utf-8 -*-

# author:yangva
# datetime:2017/12/23 0023 21:31

import re

def format_string(string): #格式化字符串,把符号格式化
    string = string.replace('++','+')
    string = string.replace('-+','-')
    string = string.replace('--','+')
    string = string.replace('*+','*')
    string = string.replace('/+','/')
    string = string.replace(' ','')
    return string

def counter_md(string): #乘除
    pattern_str2 = '\d+\.?\d*[*/][+\-]?\d+\.?\d*' #匹配乘除法,带上正负号,[]中的 - 有特殊意义,所以要转义

    while re.findall(pattern_str2,string):
        expression = re.search(pattern_str2,string).group()

        #如果有乘法,分割并分别运算
        if expression.count('*'):
            x,y = expression.split('*')
            mul_result = str(float(x)*float(y))
            string = string.replace(expression,mul_result)
            string = format_string(string)
        #如果有除法,分割并分别运算
        if expression.count('/'):
            x,y = expression.split('/')
            div_result = str(float(x)/float(y))
            string = string.replace(expression,div_result)
            string = format_string(string)
    return string

def counter_as(string): #加减
    pattern_add = '[\-]?\d+\.?\d*\+[+\-]?\d+\.?\d*' #匹配加法
    pattern_sub = '[\-]?\d+\.?\d*\-[+\-]?\d+\.?\d*' #匹配减法
    #处理加法
    while re.findall(pattern_add,string):
        add_list = re.findall(pattern_add,string) #将结果分割成一个小式子
        for add_str in add_list:  #迭代每个小式子,分别计算
            x,y = add_str.split('+')
            add_result = '+'+str(float(x)+float(y))
            string = string.replace(add_str,add_result) #得到的结果替换到式子中
    #处理减法
    while re.findall(pattern_sub,string):
        sub_list = re.findall(pattern_sub,string)
        for sub_str in sub_list:
            numbers = sub_str.split('-')
            #如果分割出来的小式子里有如-5-3的式子,会分割出['','5','3']则再分割一次
            if len(numbers) == 3:
                result = 0 #定义变量,方便后续存储结果
                for v in numbers:
                    if v:
                        result -= float(v)
            else: #正常结果,比如4-5,分割得到的则是['4','5']
                x,y = numbers
                result = float(x) - float(y)
            #替换字符串
            string = string.replace(sub_str,str(result))

    return string

def check(string): #检查合法性
    check_flag = True #标志位
    if not string.count('(') == string.count(')'):
        print('括号数量不统一')
        check_flag = False
    if re.findall('[a-zA-Z]+',string):
        check_flag = False
        print('非法字符')
        check_flag = False
    return check_flag

if __name__ == '__main__':
    #info = '20-4+9*((44-22+134/3 - (-3+33+34*5/2*5-9/3*55)-45-3)+55+3*234-2-3×57)'
    # 检验合法性
    info = input('请输入式子:')
    if check(info):
        print('info:',info)
        info = format_string(info)
        print(info)
        print('eval(info):',eval(info)) #作为与输出结果对比的验证
        while info.count('(') > 0:  #计算括号内的式子
            pattern_str = re.search('\([^()]*\)',info).group()
            #按照运算优先级,先计算乘除法的结果
            md_result = counter_md(pattern_str)
            #再计算加减法的结果
            as_result = counter_as(md_result)
            #把计算得到的结果作[1:-1]切片,把括号去掉再重新格式化替换原数据替换到式子中
            info = format_string(info.replace(pattern_str,as_result[1:-1]))
        else: #计算括号外的式子,不用再匹配直接运算
            md_result = counter_md(info)
            as_result = counter_as(md_result)
            info = info.replace(info,as_result)
print('the result is :',info.replace('+',''))

测试结果就不贴出来了,自己测试了

总结:

通过这个小项目,相信你已经对正则表达式很了解了,那么我的目的就达到了

洗礼灵魂,修炼python(80)--全栈项目实战篇(8)—— 计算器的更多相关文章

  1. 洗礼灵魂,修炼python(82)--全栈项目实战篇(10)—— 信用卡+商城项目(模拟京东淘宝)

    本次项目相当于对python基础做总结,常用语法,数组类型,函数,文本操作等等 本项目在博客园里其他开发者也做过,我是稍作修改来的,大体没变的 项目需求: 信用卡+商城: A.信用卡(类似白条/花呗) ...

  2. 洗礼灵魂,修炼python(73)--全栈项目实战篇(1)——【转载】前提准备之学习ubuntu

    本篇是为项目实战做准备,学习Linux是必备的,不然都不好意思叫全栈对吧?下面是一位资深大神写的文章,够详细,我也不用浪费时间再写了 原文链接:Ubuntu学习——第一篇 内容: 一. Ubuntu简 ...

  3. 洗礼灵魂,修炼python(78)--全栈项目实战篇(6)—— 多级目录菜单之地址管理系统

    相信各位都在在网上买过东西吧?那么今天我的主题就是写个在线购物系统,是不可能的,哈哈(后期确实有这个项目),那么购物都填写过快递地址吧?然后网上查个地址都有地址管理吧? 要求: 1.打印出省.市.县等 ...

  4. 洗礼灵魂,修炼python(86)--全栈项目实战篇(12)—— 利用socket实现文件传输/并发式聊天

    由于本篇博文的项目都很简单,所以本次开个特例,本次解析两个项目,但是都很简单的 项目一:用socket实现文件传输 本项目很简单,作为小项目的预热的,前面刚学完socket,这里马上又利用socket ...

  5. 洗礼灵魂,修炼python(79)--全栈项目实战篇(7)—— 多级目录菜单之地址管理系统升级版

    要求: 1.在上一篇的地址管理系统的基础上做升级改动 2.添加增删改的功能 3.尽量的贴近生活常识中的地址管理 分析: 需求不用多说了,干就完了 相关文件源码地址:github 这次由于要有增删改的操 ...

  6. 洗礼灵魂,修炼python(77)--全栈项目实战篇(5)—— ATM自动存取机系统

    要求: 1.完成常识中的ATM存取款机功能 2.把ATM机故障考虑进去 3.不能直接输入账户名和卡号等等信息,模拟出插银行卡让ATM机自动读取卡信息 4.密码验证超过三次错误即锁定账户 5.操作类型有 ...

  7. 洗礼灵魂,修炼python(76)--全栈项目实战篇(4)—— 购物车系统

    要求: 1.基本符合日常购物车的要求(根据你的想法开放性提升功能) 2.展示商品信息,并且可随时上新商品 3.用户购买每一样商品时都对所剩的钱做一次对比,如果够则提示“已购买”,如果不够提示“余额不足 ...

  8. 洗礼灵魂,修炼python(75)--全栈项目实战篇(3)—— 账户注册登录管理系统

    要求: 1.系统可以创建用户和登录用户,根据用户的输入不同,做出不同的反应(创建还是登录) 2.创建用户不能创建已存在的用户名 3.登录用户的操作最多只能有三次,超过三次冻结账户,每使用一次提示用户还 ...

  9. 洗礼灵魂,修炼python(81)--全栈项目实战篇(9)—— 购物商城登录验证系统

    都在线购物过吧?那么你应该体验过,当没有登录账户时,点开购物车,个人中心,收藏物品等的操作时,都会直接跳转到登录账户的界面,然后如果登录一次后就不用再登录,直到用户登出. 是的,本次项目就是做一个登录 ...

随机推荐

  1. Jvm运行时数据区

    一:运行时数据区 Java虚拟机在执行Java程序的过程中会把它管理的内存分为若干个不同的数据区域.这些区域有着各自的用途,一级创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户 ...

  2. SSL证书(HTTPS)背后的加密算法

    SSL证书(HTTPS)背后的加密算法 之前我们介绍SSL工作原理了解到当你在浏览器的地址栏上输入https开头的网址后,浏览器和服务器之间会在接下来的几百毫秒内进行大量的通信.这些复杂的步骤的第一步 ...

  3. haproxy配置示例和需要考虑的问题

    HaProxy系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.html haproxy是一个非常优秀的负载均衡工具,它的特性非常丰富,功能也非常非常 ...

  4. 解读经典《C#高级编程》第七版 Page68-79.对象和类型.Chapter3

    前言 新年好,本篇开始进入第三章,<对象和类型>,深刻理解C#的对象,对于使用好.Net类库非常重要. 01 类和结构 从使用角度看,结构和类的区别很小,比如,将结构定义转换为类,只需要将 ...

  5. Redis基础知识补充及持久化、备份介绍(二)--技术流ken

    Redis知识补充 在上一篇博客<Redis基础认识及常用命令使用(一)--技术流ken>中已经介绍了redis的一些基础知识,以及常用命令的使用,本篇博客将补充一些基础知识以及redis ...

  6. 乐观锁机制解决多层嵌套异步ajax问题

    前言 在项目中我们通常需要使用ajax异步嵌套去请求数据并做数据的展示,当我们多次快速的多次的发起ajax,因为ajax是异步的,每个ajax触发回调的时间都是不可控的,这样就会造成前面发起的ajax ...

  7. asp.net 二级域名表单认证情况下共享Cookie

    二级域名之间共享Cookie,很重要的一点就是配置,如下: domain设置为.ahdqxx.com,如果你的域名是www.ahdqxx.com,mall.ahdqxx.com,那么请设置你的doma ...

  8. asp.net-基础-20180320

    常用页面指令 <%@page%>:一个页面只能有一个 <%@Import NameSpace=“Value“%> 导入命名空间 <%@OutputCache%> 设 ...

  9. C# Winform开发以及控件开发的需要注意的,被人问怕了,都是基础常识

    我是搞控件开发的,经常被人问,所以把一些问题记录了下来!如果有人再问,直接把地址丢给他看. 一. 经常会有人抱怨Winform界面闪烁,下面有几个方法可以尽可能的避免出现闪烁 1.控件的使用尽量以纯色 ...

  10. C++中的stack类、QT中的QStack类

    C++中的stack 实现一种先进后出的数据结构,是一个模板类. 头文件 #include<stack> 用法(以int型为例): stack <int> s; //定义一个i ...