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

要求:不能使用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. [NewLife.XCode]数据层缓存(网站性能翻10倍)

    NewLife.XCode是一个有10多年历史的开源数据中间件,支持nfx/netcore,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode. 整个系列教程会大量结合示例代码和 ...

  2. jvm详情——4、分代垃圾回收详述

    虚拟机中的共划分为三个代: 年轻代(Young Generation) 年老点(Old Generation) 持久代(Permanent Generation) 其中持久代主要存放的是Java类的类 ...

  3. 在Windows Server 2008 R2上安装IIS服务

    一.Windows Server 2008 R2 介绍 1.Windows Server 2008 R2 基本概念 2.Windows Server 2008 R2 家族系列 二.VMware虚拟机安 ...

  4. 完美实现 Windows 下网络通信

    编译环境:DEV C++ 配置编译器 Windows 下 实现 Socket 编译需要 ws2_32.lib 这个库的支撑,所以我们编译前应该配置下编译器,具体配置步骤如下: Tools -> ...

  5. sql 新增 修改 删除 列操作

    IF COL_LENGTH('SYS_Department', 'CreatedBy') IS NOT NULL --判断 SYS_Department 中是否存在 CreatedBy 字段 EXEC ...

  6. 腾讯云图片鉴黄集成到C#

    官方文档:https://cloud.tencent.com/document/product/641/12422 请求官方API及签名的生成代码如下: var urlList = new List& ...

  7. JSTL_Core标记库

    一.   说明 如有转载,请标明出处 本博讲解JSTL中的core库 对标记属性进行介绍时,首先介绍必写的属性,然后带有默认值的属性,其次是其余属性,这三类属性中间用空行隔开 二:core标记库库 C ...

  8. 面试HashMap之追命5连问

    1.HashMap底层实现数据结构? 总的来说,HashMap就是数组+链表的组合实现,每个数组元素存储一个链表的头结点,本质上来说是哈希表“拉链法”的实现. HashMap的链表元素对应的是一个静态 ...

  9. js对象工厂函数与构造函数

    转自:http://www.cnblogs.com/Jener/p/5920963.html ★概述:         使用对象字面量,或者向空对象中动态地添加新成员,是最简单易用的对象创建方法.然而 ...

  10. viewer.js 视图预览demo

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...