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

要求:不能使用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. 解决AssetBundle包加载预制体时,Shader显示异常的问题

    现象: 预制体上的粒子效果显示为紫色方块. 原因:shader在打成AB包后与指定平台产生相关性,Editor中无法正常读取. 解决办法: 遍历所有加载的对象,重新赋值Shader 代码: //修正s ...

  2. nohup & expect & netstat学习

    1.nohup 用途:不挂断地运行命令,通常加上‘&’命令,& 放在命令后面表示设置此进程为后台进程.分为两种情况,如下: 在不使用密码的情况下使用nohup,只需按如下形式即可: n ...

  3. Vc数据库编程基础1

    Vc数据库编程基础1 一丶数据库 什么是数据库 数据库简单连接就是存储数据的容器. 而库则是一组容器合成的东西. 也就是存储数据的.我们编程中常常会用到数据库. 什么是数据管理系统 数据库管理系统就是 ...

  4. 【Flask-RESTPlus系列】Part2:响应编组

    0x00 内容概览 响应编组 基本使用 重命名属性 默认值 自定义字段及多值情况 Url及其他具体字段 复杂结构 列表字段 嵌套字段 api.model()工厂 clone实现复制 api.inher ...

  5. vue-router 基本使用

    参考原文:http://www.cnblogs.com/SamWeb/p/6610733.html 此链接讲了大部分常用的路由配置及使用,下星期总结

  6. gops —— Go 程序诊断分析工具

    GitHub: https://github.com/google/gops 一个用于列出和诊断分析系统中正在运行的 Go 程序的命令行工具 安装 go get -u github.com/googl ...

  7. [转]angular使用Md5加密

    本文转自:https://www.cnblogs.com/waitingbar/p/7527928.html 一.现象 用户登录时需要记住密码的功能,在前端需要对密码进行加密处理,增加安全性 二解决 ...

  8. Centos7.6 在LNMP上部署禅道

    一.下载禅道,并传到你的服务器上面的/opt文件下. http://dl.cnezsoft.com/zentao/7.3/ZenTaoPMS.7.3.stable.zbox_64.tar.gz 二.使 ...

  9. 【Spring】使用Spring和AMQP发送接收消息(下)

    上篇讲了使用RabbitMQ发送消息,本篇则来讲接收消息.在传统JMS中有两种从队列获取信息的方式,使用JmsTemplate的同步方式以及使用消息驱动pojo的异步方式.Spring AMQP也提供 ...

  10. 字符串方法之padStart和padEnd

    ECMAScript 2017 有两个新的字符串方法:padStart和padEnd;  很有用啊啊,不用写if判断啦!开心脸 padStart在字符串开始出填充,padStart(num,‘要填充的 ...