Python使用正则实现计算字符串算式


Posted in Python onDecember 29, 2019

在Python里面其实有一种特别方便实用的直接计算字符串算式的方法

那就是eval()

s = '1+2*(6/2-9+3*(3*9-9))'
print(eval(s))
#97.0

好了,我现在就是想用正则写一个类似这样功能的东西

第一步,我们拿到一个算式,例如'1+2*(6/2-9+3*(3*9-9))'

按照我们小学学的知识我们应该知道我们应该从最内层括号里面的算式开始计算

那我们怎么拿到最内层括号里面的算式呢?我们可以用正则啊

import re
pattern = re.compile(r'\([^(^)]*?\)')
s = '1+2*(6/2-9+3*(3*9-9))+(6-3)'
ret = pattern.findall(s)
print(ret)
#['(3*9-9)','(6-3)']

好了,我们现在就拿到了最内层括号以及里面的算式了,第一步完成

第二步,我们要把拿到的内容给它去掉括号

因为我们拿到的最内层的括号可能不止一个,所以我们用一个新的列表来存一下去掉括号里面的算式

ret2 = []
pattern2 = re.compile(r'\((?P<tag>.*?)\)')
for i in range(len(ret)):
 ret3 = pattern2.search(ret[i])
 ret2.append(ret3.group('tag'))
print(ret2)
#['3*9-9', '6-3']

其实到这里我们几乎已经成功一大半了

第三步,我们就要来安排我们拿到的最内层括号的算式了

这里只展示逻辑,我就只拿'3*9-9'(ret2[1])来说了

我们还是得根据算术逻辑来,先乘除,后加减

乘除

def mul_div(s):
 if '*' in s:
 s = s.split('*')
 return float(s[0]) * float(s[1])
 elif '/' in s:
 s = s.split('/')
 return float(s[0]) / float(s[1])
while True:
 pattern3 = re.compile(r'[-+*/]?(?P<tag>-?\d+(\.\d+)?[*/]-?\d+(\.\d+)?)')
 ret3 = pattern3.search(ret2[1])
 try:
 ret4 = ret3.group('tag')
 except Exception as e:
 pass
 if '*' not in ret2[1] and '/' not in ret2[1]:
 break 
 else:
 ret2[1] = ret2[1].replace(ret4, str(mul_div(ret4)))

这里的代码,可能看不明白,我来解释一下

首先mul_div()就是自己定义的一个计算乘除法的方法

因为正则表达式的约束,并且用的是search,所以一下得到的字符串只可能是字符+'/'+字符或者字符+'*'+字符。所以这里字符串切割,必定会根据乘除号切成两个元素的列表

我们算出了字符+'/'+字符或者字符+'*'+字符的值,我们就要用算出来的值替换掉正则匹配的字符串,直到这个字符串中没有乘除号

加减

def add_sub(s):
 if '+' in s:
 s = s.split('+')
 return float(s[0]) + float(s[1])
 else:
 if s[0] == '-':
  s = s[1::].split('-', 1)
  s[0] = '-' + s[0]
  return float(s[0]) - float(s[1])
 else:
  s = s.split('-', 1)
  return float(s[0]) - float(s[1])
while True:
 pattern3 = re.compile(r'-?\d+(\.\d+)?[-+]-?\d+(\.\d+)?')
 ret3 = pattern3.search(ret2[i])
 try:
 ret4 = ret3.group()
 except Exception as e:
 pass
 if '+' not in ret2[i] and '-' not in ret2[i][1::]:
 break
 else:
 ret2[i] = ret2[i].replace(ret4, str(add_sub(ret4)))

加减法和上面的乘除法没多少区别

唯一的区别就是判断退出时,一个数可能是负数,就不能直接判断负号存不存在了,就要判断除了第一个位置,其余的位置还存不存在负号

第四步

在这里,我们所有最内层括号算出来的数都在ret2这个列表里面,我们ret1中存放的是最内层括号以及里面的算式,所以我们将两者替换就可以了

def str_replace(lst1,lst2):
 for i in range(len(lst1)):
 global str1
 str1 = str1.replace(lst1[i], lst2[i])
 
str_replace(ret1,ret2)

第五步

其实到这里我们离成功就差一小步了

可能你已经发现了,我们这一套下来,就是对一个括号内的算式进行运算,如果没有括号它最后就不会对它进行操作,那我们就在字符串进来的时候给最外层套一个括号就OK了

str1 = '1+2*(6/2-9+3*(3*9-9))'
str1 = '( )'.replace(' ',str1)

然后拿到一个算式一直重复上面的几个步骤,直到没有括号。

完整代码

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
# 乘除法
def mul_div(s):
 if '*' in s:
 s = s.split('*')
 return float(s[0]) * float(s[1])
 elif '/' in s:
 s = s.split('/')
 return float(s[0]) / float(s[1])
# 加减法
def add_sub(s):
 if '+' in s:
 s = s.split('+')
 return float(s[0]) + float(s[1])
 else:
 if s[0] == '-':
  s = s[1::].split('-', 1)
  s[0] = '-' + s[0]
  return float(s[0]) - float(s[1])
 else:
  s = s.split('-', 1)
  return float(s[0]) - float(s[1])
# 替换字符串
def str_replace(lst1,lst2):
 for i in range(len(lst1)):
 global str1
 str1 = str1.replace(lst1[i], lst2[i])
# 匹配最内层括号
pattern1 = re.compile(r'\([^(^)]*?\)')
str1 = '1+2*(6/2-9+3*(3*9-9))'
str1 = '( )'.replace(' ',str1)
while True:
 if '(' not in str1 and ')' not in str1:
 break
 ret1 = pattern1.findall(str1)
 # 匹配括号内的内容
 ret2 = []
 pattern2 = re.compile(r'\((?P<tag>.*?)\)')
 for i in range(len(ret1)):
 ret = pattern2.search(ret1[i])
 ret2.append(ret.group('tag'))
 # 计算乘除法
 while True:
  pattern3 = re.compile(r'[-+*/]?(?P<tag>-?\d+(\.\d+)?[*/]-?\d+(\.\d+)?)')
  ret3 = pattern3.search(ret2[i])
  try:
  ret4 = ret3.group('tag')
  except Exception as e:
  pass
  if '*' not in ret2[i] and '/' not in ret2[i]:
  break
  else:
  ret2[i] = ret2[i].replace(ret4, str(mul_div(ret4)))
 # 计算加法
 while True:
  pattern3 = re.compile(r'-?\d+(\.\d+)?[-+]-?\d+(\.\d+)?')
  ret3 = pattern3.search(ret2[i])
  try:
  ret4 = ret3.group()
  except Exception as e:
  pass
  if '+' not in ret2[i] and '-' not in ret2[i][1::]:
  break
  else:
  ret2[i] = ret2[i].replace(ret4, str(add_sub(ret4)))
 str_replace(ret1,ret2)
print(str1)
#97.0

结束语

希望以后有人看到了,就不要吐槽我的ret1-ret4的变量命名了

还有不知道有没有写清楚,看的人能不能看明白,毕竟一晚上没睡觉,可能脑子不好使。

我这代码肯定有很多值得优化的地方,所以仅供参考。

哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈

总结

以上所述是小编给大家介绍的Python使用正则实现计算字符串算式,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Python 相关文章推荐
Linux下使用python调用top命令获得CPU利用率
Mar 10 Python
详解Python3.1版本带来的核心变化
Apr 07 Python
python模块之StringIO使用示例
Apr 08 Python
Python字符串中查找子串小技巧
Apr 10 Python
python使用MySQLdb访问mysql数据库的方法
Aug 03 Python
Python动刷新抢12306火车票的代码(附源码)
Jan 24 Python
详解python OpenCV学习笔记之直方图均衡化
Feb 08 Python
cmd运行python文件时对结果进行保存的方法
May 16 Python
Tensorflow 查看变量的值方法
Jun 14 Python
Tensorflow实现多GPU并行方式
Feb 03 Python
python+selenium+chrome实现淘宝购物车秒杀自动结算
Jan 07 Python
python+selenium实现12306模拟登录的步骤
Jan 21 Python
Django框架教程之中间件MiddleWare浅析
Dec 29 #Python
三个python爬虫项目实例代码
Dec 28 #Python
python scrapy重复执行实现代码详解
Dec 28 #Python
Python统计时间内的并发数代码实例
Dec 28 #Python
如何基于python实现脚本加密
Dec 28 #Python
python使用配置文件过程详解
Dec 28 #Python
python正则表达式匹配IP代码实例
Dec 28 #Python
You might like
PHP去掉从word直接粘贴过来的没有用格式的函数
2012/10/29 PHP
php 与 nginx 的处理方式及nginx与php-fpm通信的两种方式
2018/09/28 PHP
PHPExcel实现的读取多工作表操作示例
2020/04/14 PHP
jQuery-Easyui 1.2 实现多层菜单效果的代码
2012/01/13 Javascript
html dom节点操作(获取/修改/添加或删除)
2014/01/23 Javascript
JavaScript如何获取数组最大值和最小值
2015/11/18 Javascript
js控制TR的显示隐藏
2016/03/04 Javascript
Easyui Treegrid改变默认图标的方法
2016/04/29 Javascript
node.js平台下利用cookie实现记住密码登陆(Express+Ejs+Mysql)
2017/04/26 Javascript
angularjs实现搜索的关键字在正文中高亮出来
2017/06/13 Javascript
教你使用vue-cli快速构建的小说阅读器
2019/05/13 Javascript
解决LayUI加上form.render()下拉框和单选以及复选框不出来的问题
2019/09/27 Javascript
vue中使用rem布局代码详解
2019/10/30 Javascript
JS精确判断数据类型代码实例
2019/12/18 Javascript
Python os模块中的isfile()和isdir()函数均返回false问题解决方法
2015/02/04 Python
详解Python编程中包的概念与管理
2015/10/16 Python
Python编程实现双链表,栈,队列及二叉树的方法示例
2017/11/01 Python
Python实现PS滤镜的旋转模糊功能示例
2018/01/20 Python
python语音识别实践之百度语音API
2018/08/30 Python
Django 全局的static和templates的使用详解
2019/07/19 Python
python 实现将小图片放到另一个较大的白色或黑色背景图片中
2019/12/12 Python
Django通用类视图实现忘记密码重置密码功能示例
2019/12/17 Python
Python爬虫解析网页的4种方式实例及原理解析
2019/12/30 Python
解决TensorFlow模型恢复报错的问题
2020/02/06 Python
Python实现栈的方法详解【基于数组和单链表两种方法】
2020/02/22 Python
python让函数不返回结果的方法
2020/06/22 Python
入股协议书范本
2014/04/14 职场文书
小学优秀教育工作者事迹材料
2014/05/09 职场文书
生产助理岗位职责
2014/06/18 职场文书
人身损害赔偿协议书格式
2014/11/01 职场文书
优秀班组事迹材料
2014/12/24 职场文书
师范生小学见习总结
2015/06/23 职场文书
德能勤绩工作总结
2015/08/11 职场文书
2016创先争优活动党员公开承诺书
2016/03/24 职场文书
SQL Server 忘记密码以及重新添加新账号
2022/04/26 SQL Server
Redis高并发缓存架构性能优化
2022/05/15 Redis