600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > Python re模块 (正则表达式用法剖析详解)

Python re模块 (正则表达式用法剖析详解)

时间:2023-07-17 21:16:19

相关推荐

Python re模块 (正则表达式用法剖析详解)

阅读目录

正则表达式字符组字符(元字符)量词(个数)边界字符(也属于元字符)分组()与或 |[^]转义字符贪婪模式和非贪婪模式re模块下的常用方法re.match()re.search()re.findall()re.split()re.sub()提取与分组应用匹配标签匹配整数数字匹配

正则表达式

字符组

字符组 : [字符组]在同一个位置可能出现的各种字符组成了一个字符组,在正则表达式中用“ [ ] ”表示字符分为很多类,比如数字、字母、标点等等。假如要求一个位置"只能出现一个数字",那么这个位置上的字符只能是0、1、2...9这10个数之一

字符(元字符)

\w 包括:字母、数字、下划线;如果验证要求只允许输入:“数字和字母” 不能单独 \w 解决,还要考虑到下划线,所以只能写成[0-9a-zA-Z]

import restrd = input("please:")if re.search("^[0-9a-zA-Z]+$", strd):print("输入正确")else:print("错误")

# [/s/S] 、[/d/D]、[/w/W] 这类的可以匹配任意字符

量词(个数)

边界字符(也属于元字符)

有一些有特殊意义的元字符进入字符组中会回复它本来的意义如: . | [ ] ( )^ 匹配字符串的开始 如: ^x ,表示字符串必须以x开头, 注意:与 [^ ] 意义不同$ 匹配字符串的结束 如: x$ , 表示字符串必须以x结尾^,$ : 如果字符有多行, 且在 re.M 模式下, ^,$ 会将每一行当作一个字符串,即换行后会重新匹配\A 匹配字符串的开始, 与^ 类似, 如: \Ax ,表示字符串必须以x开头\Z 匹配字符串的结尾, 与$类似, 如: x\Z,表示字符串必须以x结尾# \A ,\Z , 在re.M模式下不会影响多行匹配\b 用来匹配单词的结尾, 如: er\b 表示单词是否以 er结束\B 用来匹配非单词的结尾, 如: er\B 表示单词中含有er,单独的以er结尾的词不行# 注意:\b 需要转意 即写成 \\bimport reres=re.findall("海.","海燕海桥海石") # ['海燕', '海桥', '海石']res=re.findall("^海.","海燕海桥海石") # 海燕res=re.findall("海.$","海燕海桥海石") # 海石res=re.findall("^海.$","海燕海桥海石") # []res=re.findall("^海.$","海燕") # ['海燕'] 这就能明白为什么 . 也属于边界字符了print(res)

分组()与或 |[^]

身份证号码是一个长度为15或18个字符的字符串,如果是15位则全部由数字组成,首位不能为0;如果是18位,则前17位全部是数字,末位可能是数字或x,下面我们尝试用正则来表示:

# 匹配任意一个邮箱 min@# x|y 表示匹配 x 或者 y# (xyz) 加上括号表示将 xyz 看成一个整体mailPattern = "\w+@\w+\.\w+"# mailPattern = "(\w+@\w+\.((com)|(cn)))" # 在re.match / re.search 下能找出

# 匹配日期 1800-01-01 --- -12-31# 1899 1999 -- # 0-[1-9] 1[0-1-2]# 0-[1-9] 1 2 - 0-9 3 0,1result=re.search("^((1[89]\d{2})|(20[01]\d)|())-((0[1-9])|(1[012]))-((0[1-9])|([12]\d)|(3[01]))$","-12-31")# 注意括号分组,或 | 的时候,每一种可能给一个括号,# 判断的每一项(年、月、日)再给一个括号print(result)import restrd = input("请按格式输入出生年月日:")if re.search("((1[89]\d{2})|(20[01]\d)|())-((0[1-9])|(1[012]))-((0[1-9])|([12]\d)|(3[01]))", strd):print("输入正确")else:print("输入格式有误,或者数值有误")

转义字符

贪婪模式和非贪婪模式

贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配

import reres = re.findall("a?", "min is a good man") # 非贪婪模式# 结果:['', '', '', '', '', '', '', 'a', '', '', '', '', '', '', '', 'a', '', '']res = re.findall("a?", "min is a good maan") # 非贪婪模式# 结果:['', '', '', '', '', '', '', 'a', '', '', '', '', '', '', '', 'a', 'a', '', '']res = re.findall("a*", "min is a good maan") # 贪婪模式# 结果:['', '', '', '', '', '', '', 'a', '', '', '', '', '', '', '', 'aa', '', '']res = re.findall("a+", "min is a good maan") # 贪婪模式# 结果:['a','aa']res = re.findall("a{3}", "min is a good maaan") # 贪婪模式# 结果:['aaa']res = re.findall("a{3}", "min is a good maaaan") # 贪婪模式# 结果:['aaa']res = re.findall("a{3,5}", "min is a good maaaaan") # 贪婪模式# 结果:['aaaaa'] 包后res = re.findall("a{3,}", "min is a good maaaaaaan") # 贪婪模式# 结果:['aaaaaaa']res = re.findall("a{,5}", "min is a good maaaaaaan") # 贪婪模式# 结果:['', '', '', '', '', '', '', 'a', '', '', '', '', '', '', '', 'aaaaa', 'aa', '', '']print(res)

单独出现 ? 非贪婪模式

出现 的第二个范围量词是“ ?” 就会变成 非贪婪模式

常用的非贪婪匹配Pattern

*? 重复任意次,但尽可能少重复+? 重复1次或更多次,但尽可能少重复?? 重复0次或1次,但尽可能少重复{n,m}? 重复n到m次,但尽可能少重复{n,}? 重复n次以上,但尽可能少重复

. * ? 的用法

. 是任意字符* 是取 0 至 无限长度? 是非贪婪模式。合在一起就是:取尽量少的任意字符,一般不会这么单独写,他大多用在:.*?x就是取前面任意长度的字符,直到一个 x 出现

re模块下的常用方法

三种模式:

re.match() 是从源字符串的 起始位置开始查找一个匹配项

re.search() 是从源字符串中找到一个匹配项

re.findall() 是从源字符串中找到所有的匹配项

flag:真正的含义re.I 使匹配对大小写不敏感re.M 多行匹配,是否影响 ^ 和 $ re.S 使 . 匹配包含换行符在内的任意字符

# re.M 实例import reres = re.findall("^min","min is a good man\nmin is a good man") # ['min']res = re.findall("^min", "min is a good man\nmin is a good man", re.M) # ['min', 'min']# 如果后面,没有加上re.M 表示看做一行字符串(不会进行换行),只能找到前面的一个“min”,加了,加了能找到两个res = re.findall("\Amin","min is a good man\nmin is a good man") # ['min']res = re.findall("\Amin","min is a good man\nmin is a good man",re.M) # ['min', 'min']# print(res)

re.match()

re.match(pattern,string,flag) # 是从源字符串的 起始位置开始查找一个匹配项pattern 要进行匹配的正则表达式string 表示的是源字符串flag 标记, 可以不写re.I 使匹配对大小写不敏感re.M 多行匹配,是否影响 ^ 和 $re.S 使 . 匹配包含换行符在内的任意字符# 如果匹配成功会返回一个对象# 如果匹配失败 会 返回None# 可以根据 结构是否为 None 来判断是否匹配成功# 可以通过这个变量的group方法来获取结果;# 如果没有匹配到,会返回None,此时如果使用group会报错

res = re.match("www","")res = re.match("www","")res = re.match("www","")res = re.match("www","wwbaidu.www,com")res = re.match("www","wwwwbaidu.www,com")res = re.match("www","")res = re.match("www","",re.I)print(res)print(type(res))>>> 匹配手机号码import rephone_number = input('please input your phone number : ')if re.match('^(13|14|15|18)[0-9]{9}$',phone_number): # 如果成功则不是Noneprint('是合法的手机号码')else:print('不是合法的手机号码')

re.search()

re.search(pattern,string,flag) # 是从源字符串中(从左往右)找到第一个匹配项pattern 要进行匹配的正则表达式string 表示的是源字符串flag 标记, 可以不写re.I 使匹配对大小写不敏感re.M 多行匹配,是否影响 ^ 和 $re.S 使 . 匹配包含换行符在内的任意字符# 多用于表单验证

res = re.search("www","")res = re.search("www","")res = re.search("www","")print(res)print(res.group)# 只匹配从左到右的第一个,得到的不是直接的结果,而是一个变量,# --需要通过这个变量的group方法来获取结果;# 如果没有匹配到,会返回None,此时如果使用group会报错

re.findall()

re.findall(pattern,string,flag) # 是从源字符串中找到所有的匹配项pattern 要进行匹配的正则表达式string 表示的是源字符串flag 标记, 可以不写re.I 使匹配对大小写不敏感re.M 多行匹配,是否影响 ^ 和 $re.S 使 . 匹配包含换行符在内的任意字符

# findall的结果是列表的形式,会将找到的多个结果放到列表中去# 注意: 如果找不到,会返回一个空列表# 注意:不能直接使用 group 方法res = re.findall("www","")res = re.findall("wwwa","") # 结果:[]print(res)print(type(res))

findall 的优先级查询:

import reret = re.findall('www.(baidu|oldboy).com', '')print(ret) # ['oldboy'] 这是因为findall会优先把匹配结果组里内容返回# 如果想要匹配结果,取消权限即可,格式:在分组内加上 ?:即 (?:正则表达式)ret = re.findall('www.(?:baidu|oldboy).com', '')print(ret) # ['']

>>> 三种模式练习import reret = re.findall('a', 'eva egon yuan') # 返回所有满足匹配条件的结果,放在列表里print(ret) # 结果 : ['a', 'a']ret = re.search('a', 'eva egon yuan').group()print(ret) # 结果 : 'a'# 函数会在字符串内 查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,# 该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。ret = re.match('a', 'abc').group() # 同search,不过在字符串开始处进行匹配print(ret)#结果 : 'a'

re.split()

# re.split()# 参数:# pattern,正则表达式, 即以某个正则来拆分# string, 被拆分的源字符串# maxsplit=0, 最大拆分次数# flags=0 标识# 正则表达式来拆分字符串strData ="wen1 is2 a3 old4 man5"lis_re = re.split(" ",strData)# list_re=re.split("\d",strData)# list_re=re.split("[0-9]",strData)# list_re=re.split(" +",strData) #注意,+前面有个空格# print(listRes) 结果:['wen1', 'is2', 'a3', 'old4', 'man5']# 结果:['wen', ' is', ' a', ' old', ' man', '']

# 如果想保留用来作切割标准的字符串:只需给它添加分组即可ret = re.split('\d+','alex83taibai40egon25')print(ret) # ['alex', 'taibai', 'egon', ''] # 最后一次切割 留下末尾一个空ret = re.split('(\d+)','alex83taibai40egon25aa')print(ret) # ['alex', '83', 'taibai', '40', 'egon', '25', 'aa']

# split的优先级查询ret=re.split("\d+","eva3egon4yuan")print(ret) #结果 : ['eva', 'egon', 'yuan']ret=re.split("(\d+)","eva3egon4yuan")print(ret) # 结果 : ['eva', '3', 'egon', '4', 'yuan']# 在匹配部分加上()之后所切出的结果是不同的,# 没有()的没有保留所匹配的项,但是有()的却能够保留了匹配的项,# 这个在某些需要保留匹配部分的使用过程是非常重要的。

re.sub()

str= "蔡徐篮球 是 xxx\n蔡徐坤歌手 是 yyy\n 肖战 是 帅哥"# re.sub()# 参数 patternrepl, 用来替换的新字符串stringcount=0, 替换的次数,默认是全部替换flags=0 # 不能修改,默认可以不写# 默认是 re.M 模式,会换行匹配所有res = re.sub("蔡徐.{,2}","肖战",str)'''肖战 是 xxx肖战手 是 yyy肖战 是 帅哥'''# subn与sub功能一致, 但是 sub是返回替 换后的新字符串,# subn返回的是元组,元组有2个元素, 元素1代表替换后的新字符串, 元素2代表的替换的次数res = re.subn("蔡徐.{,2}","肖战",str)# ('肖战 是 xxx\n肖战手 是 yyy\n 肖战 是 帅哥', 2) print(res)

提取与分组

正则表达式不仅仅有强大的匹配功能,还有强大提取功能(xyz) 将xyz看作一个整体(xyz) 将xyz看成一个小组

re.search() 模式下的分组

import res = '<a>wahaha</a>' # 标签语言 html 网页ret = re.search('<(\w+)>(\w+)</(\w+)>',s)print(ret.group(0)) # 所有的结果print(ret.group(1)) # 数字参数代表的是取对应分组中的内容print(ret.group(2))print(ret.group(3))

re.findall() 模式的分组

# 为了findall也可以顺利取到分组中的内容,有一个特殊的语法,就是优先显示分组中的内容ret = re.findall('(\w+)',s)print(ret) #['a', 'wahaha', 'a']ret = re.findall('>(\w+)<',s)print(ret) #['wahaha']strData = "010-34545546"numberPattern = "(\d{3})-(\d{8})" 结果:[('010', '34545546')]numberPattern = "((\d{3})-(\d{8}))" 结果:[('010-34545546', '010', '34545546')]# findall会将所有的组作为一个元组的元素,放在列表中,组是靠括号来分的res = re.findall(numberPattern,strData)print(res) # print(res[0]) 结果:('010', '34545546')

re.findall模式下,取消分组优先

ret = re.findall('\d+(\.\d+)?','1.234*4.3')print(ret) # 结果是:['.234', '.3']# 为什么只显示了 小数位,因为findall优先显示分组中的内容# 取消分组优先做法:在分组内加上?:(?:正则表达式)ret = re.findall('\d+(?:\.\d+)?','1.234*4.3')print(ret)str_date = "010-34545546"numberPattern = "\d{3}-\d{8}"numberPattern = "(\d{3})-(\d{8})"numberPattern = "((\d{3})-(\d{8}))"numberPattern = "(?P<First>\d{3})-(?P<Last>\d{8})"res = re.match(numberPattern,str_date)print(res)# group可以提取完整匹配的字符# () 可以将字符串分成多个组, 分组顺序是由外到里, 由前到后print(res.group()) # 默认是0print(res.group(1)) # 第一组print(res.group(2)) # 第二组#print(res.group(3)) # 第三组>>>可以给每一个分组取一个别名, 格式:(?P<别名>正则)# 获取的时候可以直接根据别名来获取print(res.group("First"))print(res.group("Last"))# groups 将() 包裹的内容进行分组提取, 将所有的分组作为元组的元素,并作为结果返回# 它只看括号res=re.match("\d{3}-\d{8}",strDate) # 这里没括号,输出结果为:()空元祖print(res.groups())

分组命名的用法

s = '<a>wahaha</b>' # 加入div标签不一致pattern = '<(\w+)>(\w+)</(\w+)>'ret = re.search(pattern,s)# print(ret.group(1) == ret.group(3)) False# 使用前面的分组 要求使用这个名字的分组和前面同名分组中的内容匹配的必须一致pattern = '<(?P<tab>\w+)>(\w+)</(?P=tab)>'ret = re.search(pattern,s)print(ret) #False>>>练习# -12-06 这种时间格式,中间的分隔符必须一致,所以可以用到命名分组# .12.6# 12 06# 12:30:30

总结

import reret = re.findall('a', 'eva egon yuan') # 返回所有满足匹配条件的结果,放在列表里print(ret) # 结果 : ['a', 'a']ret = re.search('a', 'eva egon yuan').group()print(ret) # 结果 : 'a'# 函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以# 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。ret = re.match('a', 'abc').group() # 同search,不过尽在字符串开始处进行匹配print(ret)# 结果 : 'a'ret = re.split('[ab]', 'abcd') # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割print(ret) # ['', '', 'cd']ret = re.sub('\d', 'H', 'eva3egon4yuan4', 1) # 将数字替换成'H',参数1表示只替换1个print(ret) # evaHegon4yuan4ret = re.subn('\d', 'H', 'eva3egon4yuan4') # 将数字替换成'H',返回元组(替换的结果,替换了多少次)print(ret)obj = pile('\d{3}') # 将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字ret = obj.search('abc123eeee') # 正则表达式对象调用search,参数为待匹配的字符串print(ret.group()) # 结果 : 123import reret = re.finditer('\d', 'ds3sy4784a') # finditer返回一个存放匹配结果的迭代器print(ret) # <callable_iterator object at 0x10195f940>print(next(ret).group()) # 查看第一个结果print(next(ret).group()) # 查看第二个结果print([i.group() for i in ret]) # 查看剩余的左右结果'''先编译后使用re模块的进阶 : 时间/空间compile 节省你使用正则表达式解决问题的时间编译 正则表达式 编译成 字节码在多次使用的过程中 不会多次编译ret = pile('\d+') # 已经完成编译了print(ret)res = ret.findall('alex83taibai40egon25')print(res) # 类型是“list”res = ret.search('sjkhk172按实际花费928')print(res.group())finditer 节省你使用正则表达式解决问题的空间/内存ret = re.finditer('\d+','alex83taibai40egon25')#print(ret)这是一个迭代器for i in ret:print(i.group())findall 返回列表 找所有的匹配项search 匹配就 返回一个变量,通过group取匹配到的第一个值,不匹配就返回None,group会报错match 相当于search的正则表达式中加了一个'^'spilt 返回列表,按照正则规则切割,默认匹配到的内容会被切掉sub/subn 替换,按照正则规则去寻找要被替换掉的内容,subn返回元组,第二个值是替换的次数compile 编译一个正则表达式,用这个结果去search match findall finditer 能够节省时间finditer 返回一个迭代器,所有的结果都在这个迭代器中,需要通过循环+group的形式取值 能够节省内存'''

应用

匹配标签

import reret = re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>")# 还可以在分组中利用?<name>的形式给分组起名字# 获取的匹配结果可以直接用group('名字')拿到对应的值print(ret.group('tag_name')) # 结果 :h1print(ret.group()) # 结果 :<h1>hello</h1>ret = re.search(r"<(\w+)>\w+</\1>","<h1>hello</h1>")# 如果不给组起名字,也可以用\序号来找到对应的组,表示要找的内容和前面的组内容一致# 获取的匹配结果可以直接用group(序号)拿到对应的值print(ret.group(1))print(ret.group()) # 结果 :<h1>hello</h1>

# 正则匹配所有所有tag<[^>]+> # [^>]+ 指除了“>”外,但是至少有一个字符# 匹配 open tag <[^/][^>]*> # 匹配 close tag</[^>]+># 匹配 单标签<[^>]+/>

import res="<img src='http://somehost/picture'/>"ret=re.search("<[^>]+>",s).group()print(ret) # <img src='http://somehost/picture'/>

# 匹配 双/单 引号"[^"]*" # 双/单 引号 中可以是没有任何内容

爬虫实例:爬取豆瓣排名前250的电影

import refrom urllib.request import urlopendef getPage(url): # 获取网页的字符串response = urlopen(url)return response.read().decode('utf-8')def parsePage(s):ret = com.finditer(s) # 从s这个网页源码中 找到所有符合com正则表达式规则的内容 并且以迭代器的形式返回for i in ret:yield {"id": i.group("id"),"title": i.group("title"),"rating_num": i.group("rating_num"),"comment_num": i.group("comment_num"),}def main(num): # 0 25 50 #这个函数执行10次,每次爬取一页的内容url = '/top250?start=%s&filter=' % num #每次等于多少页response_html = getPage(url) # response_html就是这个url对应的html代码 就是 strret = parsePage(response_html) # ret是一个生成器#print(ret)f = open("move_info7", "a", encoding="utf8")for obj in ret:print(obj)data = str(obj)f.write(data + "\n")f.close()com = pile('<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>''.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>', re.S)#.*? 的使用,遇到什么停止,加上 re.S模式;把要用的内容分组好count = 0for i in range(10):main(count)count += 25

对照标签

匹配整数

import reret=re.findall(r"\d+","1-2*(60+(-40.35/5)-(-4*3))")print(ret) # ['1', '2', '60', '40', '35', '5', '4', '3']ret=re.findall(r"-?\d+\.\d*|(-?\d+)","1-2*(60+(-40.35/5)-(-4*3))")print(ret) # ['1', '-2', '60', '', '5', '-4', '3']ret.remove("")print(ret) # ['1', '-2', '60', '5', '-4', '3']

匹配一个整数:\d+匹配一个小数:\d+\.\d+匹配一个整数或者小数:\d+\.\d+ | \d+ 或者 \d+(\.\d+)?

数字匹配

>>>匹配一段文本中的每行的邮箱# 只允许英文字母、数字、下划线、英文句号、以及中划线组成# 例:zhoujielun-001@^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$# 名称允许汉字、字母、数字,域名只允许英文域名# 例:周杰伦001Abc@^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$# 邮箱规则:# @之前必须有内容且只能是字母(大小写)、数字、下划线(_)、减号(-)、点(.)# @和最后一个点(.)之间必须有内容且只能是字母(大小写)、数字、点(.)、减号(-),# --且两个点不能挨着# 最后一个点(.)之后必须有内容且内容只能是字母(大小写)、数字且长度为大于等于2个字# --节,小于等于6个字节[0-9a-zA-Z][\w\-.]+@[a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]+)*\.[A-Za-z0-9]{2,6}>>>匹配一段文本中的每行的时间字符串,比如:‘1990-07-12’;分别取出1年的12个月(^(0?[1-9]|1[0-2])$)、一个月的31天:^((0?[1-9])|((1|2)[0-9])|30|31)$>>>匹配qq号。(腾讯QQ号从10000开始) [1,9][0,9]{4,}>>>匹配一个浮点数。 ^(-?\d+)(\.\d+)?$ 或者 -?\d+\.?\d*>>>匹配汉字。 ^[\u4e00-\u9fa5]{0,}$ >>>匹配出所有整数 >>> 1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))# 从上面算式中匹配出内层没有其他小括号的表达式\([^()]+\)>>>从类似9-1000/3+7/3*99/4*2998+10*568/14的表达式中匹配出从左到右第一个乘法或除法\d+[*/]\d+

模拟一个计算器功能

import redef atmo_cal(exp): # 原子计算器,最小单位不可再拆分了,处理乘除法,如:5*0.6;6/2if "*" in exp:a, b = exp.split("*") # 最小了,只有两位return str(float(a) * float(b))elif "/" in exp:a, b = exp.split("/")return str(float(a) / float(b))def add_sub(exp): # 计算加减法ret = re.findall("[-+]?\d+(?:\.\d+)?", exp) # 取消分组优先,得到一个列表exp_sum = 0for i in ret:exp_sum += float(i)return exp_sumdef mul_div(exp): # 计算乘除法while True:ret = re.search("\d+(?:\.\d+)?[/*]-?\d+(?:\.\d+)?", exp)# 用的是search,所以从左往右匹配到第一项就返回结果if ret:atmo_exp = ret.group() # 分组取出原子每一项res = atmo_cal(atmo_exp) # 调用原子计算器,打印结果为"-22.0"# "2-1*-22+3-4/-5" "-22.0" 替换原式子中的位置即:"2--22.0-3-4/-5"exp = exp.replace(atmo_exp, res) # 参数位置 旧的,新的 将旧的替换成新的else: # 2--22.0-3--0.8 乘除法都运算完毕了return expdef format(exp):exp = exp.replace('--', '+')exp = exp.replace('+-', '-')exp = exp.replace('-+', '-')exp = exp.replace('++', '+')return expdef cal(exp): # 将乘法或者除法匹配出来;"2-1*-22-3-4/-5" 用来计算用的exp = mul_div(exp) # 调用乘除法函数exp = format(exp) # 调用格式化函数后:2+22.0-3+0.8exp_sum = add_sub(exp) # 调用计算加法的函数 21.8return exp_sum # 返回结果# print(cal("2-1*-22-3-4/-5"))def main(exp): # 主函数exp = exp.replace(" ", "") # 去掉用户输入内容的空格while True:ret = re.search("\([^()]+\)", exp) # (-40/5)if ret:inner_bracket = ret.group() # 这里可能得到各种运算res = str(cal(inner_bracket))# print(inner_bracket,type(res))exp = exp.replace(inner_bracket, res)# print(exp) 再格式化下 1-2*((60-30+-8.0*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))exp = format(exp)# print(exp)else:break# print(exp,type(exp)) ;1-2*-1388335.8476190479 <class 'str'>return cal(exp)s = '1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )'ret = main(s)print(ret, type(ret))print(eval(s), type(eval(s))) # 用户可能再用到,所以像eval一样返回原来的格式# 2776672.6952380957 <class 'float'># 2776672.6952380957 <class 'float'>

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。