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 相关文章推荐
Python3读取文件常用方法实例分析
May 22 Python
安装ElasticSearch搜索工具并配置Python驱动的方法
Dec 22 Python
python urllib爬取百度云连接的实例代码
Jun 19 Python
Python矩阵常见运算操作实例总结
Sep 29 Python
wxPython实现窗口用图片做背景
Apr 25 Python
Pandas:DataFrame对象的基础操作方法
Jun 07 Python
解决pyttsx3无法封装的问题
Dec 24 Python
在PyCharm导航区中打开多个Project的关闭方法
Jan 17 Python
python 图片去噪的方法示例
Jul 09 Python
Jupyter notebook无法导入第三方模块的解决方式
Apr 15 Python
细说NumPy数组的四种乘法的使用
Dec 18 Python
python使用pymysql模块操作MySQL
Jun 16 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
第十节 抽象方法和抽象类 [10]
2006/10/09 PHP
cmd下运行php脚本
2008/11/25 PHP
基于HTTP长连接的&quot;服务器推&quot;技术的php 简易聊天室
2009/10/31 PHP
PHP解码unicode编码的中文字符代码分享
2014/08/13 PHP
php以post形式发送xml的方法
2014/11/04 PHP
php通过array_push()函数添加多个变量到数组末尾的方法
2015/03/18 PHP
Laravel框架中VerifyCsrfToken报错问题的解决
2017/08/30 PHP
JavaScript Event学习第九章 鼠标事件
2010/02/08 Javascript
js分解url参数(面向对象-极简主义法应用)
2012/08/09 Javascript
解析javascript系统错误:-1072896658的解决办法
2013/07/08 Javascript
基于MVC3方式实现下拉列表联动(JQuery)
2013/09/02 Javascript
多个jquery.datatable共存,checkbox全选异常的快速解决方法
2013/12/10 Javascript
jQuery实现查找链接文字替换属性的方法
2016/06/27 Javascript
js原生Ajax的封装和原理详解
2017/03/11 Javascript
javascript 中的try catch应用总结
2017/04/01 Javascript
vue+canvas实现炫酷时钟效果的倒计时插件(已发布到npm的vue2插件,开箱即用)
2018/11/05 Javascript
vue与bootstrap实现简单用户信息添加删除功能
2019/02/15 Javascript
nodejs文件夹深层复制功能
2019/09/03 NodeJs
使用nodejs实现JSON文件自动转Excel的工具(推荐)
2020/06/24 NodeJs
使用Python脚本将绝对url替换为相对url的教程
2015/04/24 Python
python动态性强类型用法实例
2015/05/09 Python
开源Web应用框架Django图文教程
2017/03/09 Python
matplotlib 纵坐标轴显示数据值的实例
2018/05/25 Python
python实现flappy bird小游戏
2018/12/24 Python
python正则表达式去除两个特殊字符间的内容方法
2018/12/24 Python
详解用Python实现自动化监控远程服务器
2019/05/18 Python
Python实现图片识别加翻译功能
2019/12/26 Python
Python字符串格式化f-string多种功能实现
2020/05/07 Python
Django通过设置CORS解决跨域问题
2020/11/26 Python
用HTML5制作视频拼图的教程
2015/05/13 HTML / CSS
槐乡的孩子教学反思
2014/04/27 职场文书
导师对论文的学术评语
2015/01/04 职场文书
四风之害观后感
2015/06/09 职场文书
2016年毕业实习心得体会范文
2015/10/09 职场文书
音乐课《小猫钓鱼》教学反思
2016/02/18 职场文书
CSS中妙用 drop-shadow 实现线条光影效果
2021/11/11 HTML / CSS