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 相关文章推荐
基于Django contrib Comments 评论模块(详解)
Dec 08 Python
Python获取本机所有网卡ip,掩码和广播地址实例代码
Jan 22 Python
python3操作微信itchat实现发送图片
Feb 24 Python
使用Python通过win32 COM实现Word文档的写入与保存方法
May 08 Python
解决pyinstaller打包exe文件出现命令窗口一闪而过的问题
Oct 31 Python
详解python:time模块用法
Mar 25 Python
在pycharm中显示python画的图方法
Aug 31 Python
python argparser的具体使用
Nov 10 Python
python使用html2text库实现从HTML转markdown的方法详解
Feb 21 Python
Python线程协作threading.Condition实现过程解析
Mar 12 Python
pytorch model.cuda()花费时间很长的解决
Jun 01 Python
Python 实现Mac 屏幕截图详解
Oct 05 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之第四天
2006/10/09 PHP
php地址引用(php地址引用的效率问题)
2012/03/23 PHP
PHP的构造方法,析构方法和this关键字详细介绍
2013/10/22 PHP
php隐藏实际地址的文件下载方法
2015/04/18 PHP
php简单创建zip压缩文件的方法
2016/04/30 PHP
php从数据库中读取特定的行(实例)
2017/06/02 PHP
PHP cookie,session的使用与用户自动登录功能实现方法分析
2019/06/05 PHP
JSQL 基于客户端的成绩统计实现方法
2010/05/05 Javascript
jquery下为Event handler传递动态参数的代码
2011/01/06 Javascript
javascript函数作用域学习示例(js作用域)
2014/01/13 Javascript
js实现照片墙功能实例
2015/02/05 Javascript
js操作css属性实现div层展开关闭效果的方法
2015/05/11 Javascript
浅谈javascript的Touch事件
2015/09/27 Javascript
探究Vue.js 2.0新增的虚拟DOM
2016/10/20 Javascript
vue 的点击事件获取当前点击的元素方法
2018/09/15 Javascript
vue实现多条件和模糊搜索功能
2019/05/28 Javascript
菜鸟使用python实现正则检测密码合法性
2016/01/05 Python
深入浅析python继承问题
2016/05/29 Python
python实现txt文件格式转换为arff格式
2018/05/31 Python
python中字符串的操作方法大全
2018/06/03 Python
python调用c++ ctype list传数组或者返回数组的方法
2019/02/13 Python
IronPython连接MySQL的方法步骤
2019/12/27 Python
Pycharm最常用的快捷键及使用技巧
2020/03/05 Python
通过代码实例了解Python sys模块
2020/09/14 Python
Python包资源下载路径报404解决方案
2020/11/05 Python
python实现文件分片上传的接口自动化
2020/11/19 Python
用python对excel进行操作(读,写,修改)
2020/12/25 Python
高中数学教师求职信
2013/10/30 职场文书
人民教师求职自荐信
2014/03/12 职场文书
团日活动总结书
2014/05/08 职场文书
副职竞争上岗演讲稿
2014/05/12 职场文书
冬季施工防火方案
2014/05/17 职场文书
品牌转让协议书
2014/08/20 职场文书
新教师个人工作总结
2015/02/06 职场文书
实名检举信范文
2015/03/02 职场文书
导游词之井冈山
2019/11/20 职场文书