• Python使用正则匹配re实现eval计算器


     Python使用正则匹配re实现eval计算器

    一、 概述

      本文仅为记录自己学习过程中踩过的坑,不喜勿喷。

    二、方案思路

      string = '2 * 60 - 30 + (-40.0/5) * (9-2*5/2+9/3*10/4*2+10*5/5 -(-4*3)) -(-4*3)/(16-3*2)'

      1.计算未出现括号情况下的结果

      2.把最里层括号找出来,计算后替换回原字符串

      3.重复计算到没有括号为止,再次用未出现括号方法计算,得出最后结果

    三、源码

      1 #!-*- coding:utf-8 -*-
      2 #__anthor__:"Klay Zhu"
      3 #date: 2018/7/13
      4 import re
      5 PREC = '{:+.5f}'#计算精度 5代表5位小数
      6 obj_mul = re.compile(r"(-?d+.?d*)*(-?d+.?d*)") # 乘法
      7 obj_div = re.compile(r"(-?d+.?d*)/(-?d+.?d*)")  # 除法
      8 obj_add = re.compile(r"(-?d+.?d*)+(-?d+.?d*)") # 加法
      9 obj_sub = re.compile(r"(-?d+.?d*)-(-?d+.?d*)")  # 减法
     10 obj_f   = re.compile(r"(?+?-?d+)?")               # 检查括号内是否运算完毕规则
     11 obj_k   = re.compile(r"([^()]+)")                   # 寻找最内层括号规则
     12 obj_che = re.compile(r"[^0-9+-*/()s.]")             # 匹配输入非法字符
     13 def count(string):
     14     """
     15     计算没有括号的式子
     16     :param string:
     17     :return:
     18     """
     19     string = rm_SP(string)
     20     while True:
     21         if obj_div.search(string) :# 除法(必须先判断)
     22             exp = re.split(r'/',obj_div.search(string).group())
     23             answer = float(exp[0]) / float(exp[1])
     24             string = obj_div.sub(PREC.format(answer),string,1)
     25         elif obj_mul.search(string) :# 乘法
     26             exp = re.split(r'*', obj_mul.search(string).group())
     27             answer = float(exp[0]) * float(exp[1])
     28             string = obj_mul.sub(PREC.format(answer), string,1)
     29         elif obj_add.search(string) :# 加法
     30             exp = re.split(r'+', obj_add.search(string).group())
     31             answer = float(exp[0]) + float(exp[1])
     32             string = obj_add.sub(PREC.format(answer), string,1)
     33         elif obj_sub.search(string) :# 减法
     34             exp = re.split(r'-', obj_sub.search(string).group())
     35             if exp[0] =="":#前面有负号的时候
     36                 answer = 0-float(exp[1]) - float(exp[2])
     37                 string = obj_sub.sub(PREC.format(answer), string, 1)
     38             else:
     39                 answer = float(exp[0]) - float(exp[1])
     40                 string = obj_sub.sub(PREC.format(answer), string,1)
     41         elif obj_f.search(string):# 结束循环
     42             string = re.sub('(|)|', '', string)
     43             return string
     44         string = rm_SP(string) #去除多余的符号
     45 
     46 def rm_SP(string):
     47     """
     48     去除符号
     49     :param str:
     50     :return:
     51     """
     52     string = re.sub('++','+',string)
     53     string = re.sub('--', '+', string)
     54     string = re.sub('+-', '-', string)
     55     string = re.sub('-+', '-', string)
     56     string = re.sub('/+', '/', string)
     57     string = re.sub('*+', '*', string)
     58     string = re.sub('^+', '', string)
     59     return string
     60 
     61 def rm_PAR(string):
     62     """
     63     计算括号里
     64     :param string:
     65     :return:
     66     """
     67     string = rm_SP(string)
     68     list_m = obj_k.findall(string)
     69     list_map= map(count,list_m)
     70     for i in range(len(list_m)):
     71         string = string.replace(list_m[i],list_map.__next__(),1)
     72     return string
     73 def main(string):
     74     """
     75     主函数,循环计算
     76     :param string:
     77     :return:
     78     """
     79     checkout(string)
     80     string = re.sub('s', '', string) #去掉空格
     81     while True:
     82         if obj_k.search(string):#是否还存在括号
     83             string = rm_PAR(string)
     84             continue
     85         answer = count(string)
     86         return answer
     87 
     88 def checkout(string):
     89     """
     90     校验输入是否合法
     91     :param string:
     92     :return:
     93     """
     94     if len(re.findall('(',string)) != len(re.findall(')',string)):
     95         print("括号不成对")
     96         exit()
     97     elif obj_che.findall(string) != [] :
     98         print(obj_che.findall(string))
     99         print("输入中有非法字符")
    100         exit()
    101 
    102 if __name__ == '__main__':
    103     string = r'2 * 60 - 30 + (-40.0/5) * (9-2*5/2+9/3*10/4*2+10*5/5 -(-4*3)) -(-4*3)/(16-3*2)'#-236.80000
    104     # string = input("请输入需要计算的式子:")
    105     answer = main(string)
    106     print("最后答案:", answer)
    View Code

    四、记录踩下的坑

    1.使用map()计算出结果后替换回原字符串时,由于上一次替换后满足下次正则匹配,所以被深深坑了一波!后来改用完全匹配就没出现这个问题了。

    2.在处理负数转换成字符串的时候,可以用format() ,具体如何使用请百度。

  • 相关阅读:
    android 多行文本显示的textView
    FastJson 打Release 包解析失败
    Android 颜色透明度换算
    Android Stadio 导入moudle 不显示
    Android onConfigurationChanged 收不到回调
    如何在TortoiseGit中使用ssh-keygen生成的key
    Android 判断屏幕方向一个大坑
    requestLayout 无效
    Android stadio Switch repository Android stadio切换仓库
    Windows usb设备正在使用中
  • 原文地址:https://www.cnblogs.com/Klay/p/9309841.html
Copyright © 2020-2023  润新知