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 相关文章推荐
wxPython中文教程入门实例
Jun 09 Python
python使用7z解压apk包的方法
Apr 18 Python
Python 判断是否为质数或素数的实例
Oct 30 Python
Python内建模块struct实例详解
Feb 02 Python
python opencv实现切变换 不裁减图片
Jul 26 Python
详解分布式任务队列Celery使用说明
Nov 29 Python
情人节快乐! python绘制漂亮玫瑰
Aug 18 Python
Python使用MyQR制作专属动态彩色二维码功能
Jun 04 Python
Numpy 中的矩阵求逆实例
Aug 26 Python
Pandas之read_csv()读取文件跳过报错行的解决
Apr 21 Python
Keras 在fit_generator训练方式中加入图像random_crop操作
Jul 03 Python
Sublime Text3最新激活注册码分享适用2020最新版 亲测可用
Nov 12 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使用内置函数生成图片的方法详解
2016/05/09 PHP
jquery autocomplete自动完成插件的的使用方法
2010/08/07 Javascript
document.all的一个比较完整的总结及案例
2013/01/31 Javascript
javascript date格式化示例
2013/09/25 Javascript
键盘KeyCode值列表汇总
2013/11/26 Javascript
js报$ is not a function 的问题的解决方法
2014/01/20 Javascript
jQuery获得IE版本不准确webbrowser的解决方法
2014/02/23 Javascript
教你用AngularJS框架一行JS代码实现控件验证效果
2014/06/23 Javascript
JavaScript编程中的Promise使用大全
2015/07/28 Javascript
学习JavaScript设计模式(多态)
2015/11/25 Javascript
require.js配合插件text.js实现最简单的单页应用程序
2016/07/12 Javascript
使用React实现轮播效果组件示例代码
2016/09/05 Javascript
EasyUI在Panel上动态添加LinkButton按钮
2017/08/11 Javascript
通过vue-cli3构建一个SSR应用程序的方法
2018/09/13 Javascript
Vue组件间通信方法总结(父子组件、兄弟组件及祖先后代组件间)
2019/04/17 Javascript
vue-cli3.0实现一个多页面应用的历奇经历记录总结
2020/03/16 Javascript
简单了解vue 插值表达式Mustache
2020/07/22 Javascript
Python、Javascript中的闭包比较
2015/02/04 Python
用Python的Tornado框架结合memcached页面改善博客性能
2015/04/24 Python
介绍Python中的__future__模块
2015/04/27 Python
Python的Django框架中从url中捕捉文本的方法
2015/07/20 Python
Python中return语句用法实例分析
2015/08/04 Python
python杀死一个线程的方法
2015/09/06 Python
Python while 循环使用的简单实例
2016/06/08 Python
Python批量查询域名是否被注册过
2017/06/21 Python
django 使用 request 获取浏览器发送的参数示例代码
2018/06/11 Python
Python超越函数积分运算以及绘图实现代码
2019/11/20 Python
Python 实现加密过的PDF文件转WORD格式
2020/02/04 Python
CSS3实现大小不一的粒子旋转加载动画
2016/04/21 HTML / CSS
canvas 下载二维码和图片加水印的方法
2018/03/21 HTML / CSS
个人工作表现评价材料
2014/09/21 职场文书
医院领导班子整改方案
2014/10/01 职场文书
大学感恩节活动策划方案
2014/10/11 职场文书
2016寒假社会实践心得体会范文
2015/10/09 职场文书
MySQL系列之二 多实例配置
2021/07/02 MySQL
macos系统如何实现微信双开? mac登录两个微信以上微信的技巧
2022/07/23 数码科技