python没有正则需要导入re模块调用.正则表达式是为了匹配字符串,动态模糊的匹配,只要有返回就匹配到了, 没返回就没匹配到,前面是格式后面是字符串
最常用的匹配语法:
re.match()#从头开始匹配(两种方式:简单,分组)
re.search()#浏览全部字符,匹配第一个符合规则的字符串
re.findall()#把所有匹配到的字符放到以列表中的元素返回
re.split()#以匹配到的字符当做列表分隔符
re.sub()#匹配字符并替换
re.finditer()
扩展:
re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
M(MULTILINE): 多行模式,改变'^'和'$'的行为
S(DOTALL): 点任意匹配模式,改变'.'的行为 import re
res=re.match('^zc','zcok168')
print(res)
print(res.group())#打印匹配的内容 '.' 默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
'^' 匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
'$' 匹配字符结尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也可
'*' 匹配*号前的字符0次或多次,re.findall("ab*","cabb3abcbbac") 结果为['abb', 'ab', 'a']
'+' 匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']
'?' 匹配前一个字符1次或0次
'{m}' 匹配前一个字符m次
'{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']
'|' 匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 先匹配第一个结果'ABC',如果使用findall就没有group()方法
'(...)' 分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c
'\A' 只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的
'\Z' 匹配字符结尾,同$
'\d' 匹配数字0-9
'\D' 匹配非数字的所有字符
'\w' 匹配[A-Za-z0-9]
'\W' 匹配非[A-Za-z0-9]
'\s' 匹配空白字符、\t、\n、\r , re.search("\s+","ab\t\n \r")结果:'\t\n \r'>
'(?P<name>...)' 分组匹配 re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","").groupdict("city")结果: {'province': '', 'city': '', 'birthday': ''} 总结:
+ 表示 会按照它前面字符的样式来打印多个
. 表示 打印除\n(换行)外的所有字符
.+ 组合才会全部包括后面的数字 打印之后的所有字符
[a-z] 表示 打印一个小写字母;[A-Z]表示:打印一个大写字母
[a-z] + [A-Z] 可以组合起来用
Eg:("z[a-z]+[A-Z]+","jiang123zhongzHenzhongzhen1232424124zhongzhen")
一、z[a-z]+[A-Z]+.+ 就是将上面从z开始打印完 结果:zhongzHenzhongzhen1232424124zhongzhen
二、"z[a-zA-Z]+\d+" 就是将上面从z开始打印到结果:zhongzHenzhongzhen1232424124
练习例子:
import re
ser=re.search("aal?","aaexaaaa")#匹配问号前面一个字符一次或0次,如果问号前面字符匹配不到会匹配到后面,结果:aa
print(ser) ser1=re.search("[0-9]{3}","aa1x2a345aa")#匹配前一个字符M次,结果:345
print(ser1) ser1=re.findall("[0-9]{1,3}","aa1x2a345aa")#匹配所有字符放到列表中返回,结果:['1', '2', '345']
print(ser1) ser2=re.search("(abc){2}(\|\|=){2}",'alexabcabc||=||=')#需要\来转义,结果:'abcabc||=||='
print(ser2) ser3=re.search("\A[0-9]+[a-z]\Z","123a")#结果:'123a'
print(ser3) ser4=re.search("\s+","ab\t\n \r")#结果:'\t\n \r'
print(ser4) ser5=re.search("(?P<id>[0-9]+)(?P<name>[a-zA-Z]+)","abcd1234daf@34").groupdict('name')
print(ser5)#结果:{'id': '1234', 'name': 'daf'} ser6=re.search("(?P<province>[0-9]{3})(?P<city>[0-9]{3})(?P<birthday>[0-9]{4})","").groupdict()
print(ser6)#分组匹配,{'province': '610', 'city': '331', 'birthday': '1989'} ser6=re.split("[0-9]+","abc12de3f45GH")
print(ser6)#按数字进行分割,['abc', 'de', 'f', 'GH'] ser7=re.sub("[0-9]+","|","abc12de3f45GH",count=2)#count=2也和写成2
print(ser7)#匹配字符并替换所有数字,加count=2只匹配前2个,abc|de|f45GH ser8=re.search("[a-z]+","abcdE",flags=re.I)
print(ser8)#大小写都匹配,'abcdE' 重点知识:
res=re.search("aaaaz?","azhangaaaa")# 表示 ?前面的那个 z有和没有都可以 但是z?前面的那些a必须都要匹配到,如果匹配不到就 报错,可以匹配到就输出
res =re.findall("[0-9]{1,3}","z1h23a456n7g8")#re.findall() 没有group方法
print(res)#结果为:['1', '23', '456', '7', '8']
res =re.findall("[0-9]{1,2}","z1h23a456n7g8")
print(res)#结果为:['1', '23', '45', '6', '7', '8']
res =re.findall("[0-9]{3}","z1h23a456n7g8")
rint(res)#结果为:['456'] res=re.search("(?P<province>[0-9]{2})(?P<shi>[0-9]{2})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","")
print(res.groupdict()) #其中的 ?P 表示语法 <key>[范围]{几位} 结果为:{'province': '37', 'shi': '14', 'city': '81', 'birthday': '1993'} 并且还可以再加几组字典
print(res.groupdict()['city']) # 相当于取出字典中的key=’city’结果为:81
re模块用法案例
res =re.search("[a-z]+","zhangSHuai",flags =re.I)# flag =re.I 忽略大小写 结果为:zhangSHuai
print(res.group()) """re(正则表达式)就是用于动态匹配的 如果是一个固定值,就不需要通过re来进行 直接通过 wang in wangmazi:就可以进行匹配 """ import re
"""re.match 的用法:就是默认从头开始的,
^ 表示要匹配字符开头 故而 ^ 在match中没有用
第一个""写的是要匹配的内容,后面的""写的是匹配度的范围
res =re.match("^wang","wang mazi")
print(res) #如果有返回结果 就表示匹配到了 如果没有匹配到就返回 None
print(res.group())#通过res.group()来查看匹配到什么""" """ \d+的用法
\ 表示后面是用于正则的语法,\d表示一个数字 结果为:wang2,
\d+表示一个或多个数字结果为:wang234
res =re.match("wang\d+","wang234 mazi ")
print(res.group())""" """ . 的用法
res =re.match(".","@wang234 mazi ")# . 默认匹配除\n之外的任意一个字符 在此处打印 @
# res =re.match(".+","wang234 mazi ")# + 表示打印后面的多个 故而: .+ 打印全部
# res =re.match(".\d","w1ang234 mazi ")#如果第一位是 w 第二个为数字就可以执行,否则就会报错
# res =re.match("^w","wang234 mazi ")
print(res.group())""" """re.serach的用法 表示从整个内容中搜查 这是会用到 ^ 符号"""
#res = re.search("z.+n","jiang123zhongzhen123a")#从z开始 通过.+就z之后一直到
#后面的 n 如果前面+之后没有n就会包括123 #res =re.search("z[a-z]+.+2","jiang123zhong zhen123a")
"""
[a-z]输出一个在a到z之间的一个字符, + 表示多个字符,第一个 + 从o取到g
然后 . 表示一个除\n(换行)外的任意一个字符取出空格, 第二个加号表示
从 z 一直往后取到加号后面的截止字符 结果为:zhong zhen12
res =re.search("z[a-z]+[A-Z]+.+","jiang123zhongzHenzhongzhen1232424124zhongzhen")#输出结果为:zhongZhenzhongzhen
#res =re.search("z[a-zA-Z]+\d+","jiang123zhongzHenzhongzhen1232424124zhongzhen")
res =re.search("#.+#","123#hello#")#结果为:#hello#
print(res.group())"""
# res=re.search("aaaaa?","azhangaaaa")#表示?前面的那个a有和没有都可以 但是a?前面的那些a必须要匹配到
# print(res.group()) """re.findall() 匹配不相连的多个数字 并且没有group()方法
#res =re.findall("[0-9]{1,2}","z1h23a456n7g8")#结果为:['1', '23', '45', '6', '7', '8']
#res =re.findall("[0-9]{1,3 }","z1h23a456n7g8")#结果为:['1', '23', '456', '7', '8']
res =re.findall("[0-9]{3}","z1h23a456n7g8")#结果为:['456']
print(res)""" res=re.search("abc|ABC","ABCBabcdB")#先匹配小写或者再匹配大写 返回结果:ABC
res=re.search("abc{2}","abccadf") #匹配abc并且c匹配两次 即:必须要有abcc才可以才返回,否则报错
res =re.search("(abc){2}","abcabcadf")#同上 将abc当做一个小组,同时匹配两次 即:abcabc 否则报错
res =re.search("(abc){2}\|","abcabcadf")#同理 \ 表示转义符,代表不要将 |当做或l来处理 有abcabc| 时才输出,否则报错
res =re.search("(abc){2}(\|\|=){2}","sdabcabc||=||=adf")# 每一个 \| 都要用输出结果为:abcabc||=||=
res =re.search("\A[0-9]+[a-z]+\Z","123sdf")#\A等同于 ^ ,表示从第一个元素开始,从第一个为数字,然后经过几个数,然后经过几个字母\Z表示以 字母结束
res =re.search("\D+","123&%*- A@ \\n") #\D匹配不是数字的任意一个字符 特殊字符可以 换行也可以 结果为:&%*- A@ \n
res =re.search("\w+","123&%*- A@ \\n")# 小写的 \w只匹配数字和字母 结果为:123
res =re.search("\W+","123&%*- A@ \\n")#只匹配特殊字符 结果为:&%*-
#res =re.search("\s+","\r\t\n123&%*- A@ ")
res=re.search("(?P<province>[0-9]{2})(?P<shi>[0-9]{2})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","")
#其中的 ?P 表示语法 <key>[范围]{几位} 结果为:{'province': '37', 'shi': '14', 'city': '81', 'birthday': '1993'}
print(res.groupdict()['city'])
res =re.split("[0-9]+","ab2h4h35g42g") # 因为[0-9]只是一个字符,故而表示将后面的内容# 以数字分隔开,然后是单个数字的去掉,
多个数字的就以空字符显示出来并与分隔开的字母形成列表 结果为:['ab', 'h', 'h', '', 'g', '', 'g']
res =re.sub("[0-9]+","|","ab2h4h35g42g",count=2)
print(res)
res =re.search("[a-z]+","zhangSHuai",flags =re.I)# flag =re.I 忽略大小写 结果为:zhangSHuai
print(res.group())
计算器作业
1. 实现加减乘除及拓号优先级解析
2. 用户输入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等类似公式后,必须自己解析里面的(),+,-,*,/符号和公式(不能调用eval等类似功能偷懒实现),运算后得出结果,结果必须与真实的计算器所得出的结果一致
3. import re
import functools
def minus_operator_handler(formula):
'''处理一些特殊的减号运算'''
minus_operators = re.split("-", formula)
calc_list = re.findall("[0-9]", formula)
if minus_operators[0] == '': # 第一值肯定是负号
calc_list[0] = '-%s' % calc_list[0]
res = functools.reduce(lambda x, y: float(x) - float(y), calc_list)
print("\033[33;1m减号[%s]处理结果:\033[0m" % formula, res)
return res def remove_duplicates(formula):
formula = formula.replace("++", "+")
formula = formula.replace("+-", "-")
formula = formula.replace("-+", "-")
formula = formula.replace("--", "+")
formula = formula.replace("- -", "+")
return formula def compute_mutiply_and_dividend(formula):
'''算乘除,传进来的是字符串噢'''
operators = re.findall("[*/]", formula)
calc_list = re.split("[*/]", formula)
res = None
for index, i in enumerate(calc_list):
if res:
if operators[index - 1] == "*":
res *= float(i)
elif operators[index - 1] == "/":
res /= float(i)
else:
res = float(i) print("\033[31;1m[%s]运算结果=\033[0m" % formula, res)
return res def handle_minus_in_list(operator_list, calc_list):
'''有的时候把算术符和值分开后,会出现这种情况 ['-', '-', '-'] [' ', '14969037.996825399 ', ' ', '12.0/ 10.0 ']
这需要把第2个列表中的空格都变成负号并与其后面的值拼起来,
'''
for index, i in enumerate(calc_list):
if i == '': # 它其实是代表负号,改成负号
calc_list[index + 1] = i + calc_list[index + 1].strip() def handle_special_occactions(plus_and_minus_operators, multiply_and_dividend):
'''有时会出现这种情况 , ['-', '-'] ['1 ', ' 2 * ', '14969036.7968254'],2*...后面这段实际是 2*-14969036.7968254,需要特别处理下'''
for index, i in enumerate(multiply_and_dividend):
i = i.strip()
if i.endswith("*") or i.endswith("/"):
multiply_and_dividend[index] = multiply_and_dividend[index] + plus_and_minus_operators[index] + \
multiply_and_dividend[index + 1]
del multiply_and_dividend[index + 1]
del plus_and_minus_operators[index]
return plus_and_minus_operators, multiply_and_dividend def compute(formula):
'''这里计算是的不带括号的公式''' formula = formula.strip("()") # 去除外面包的拓号
formula = remove_duplicates(formula) # 去除外重复的+-号
plus_and_minus_operators = re.findall("[+-]", formula)
multiply_and_dividend = re.split("[+-]", formula) # 取出乘除公式
if len(multiply_and_dividend[0].strip()) == 0: # 代表这肯定是个减号
multiply_and_dividend[1] = plus_and_minus_operators[0] + multiply_and_dividend[1]
del multiply_and_dividend[0]
del plus_and_minus_operators[0] plus_and_minus_operators, multiply_and_dividend = handle_special_occactions(plus_and_minus_operators,
multiply_and_dividend)
for index, i in enumerate(multiply_and_dividend):
if re.search("[*/]", i):
sub_res = compute_mutiply_and_dividend(i)
multiply_and_dividend[index] = sub_res
# 开始运算+,-
print(multiply_and_dividend, plus_and_minus_operators)
total_res = None
for index, item in enumerate(multiply_and_dividend):
if total_res: # 代表不是第一次循环
if plus_and_minus_operators[index - 1] == '+':
total_res += float(item)
elif plus_and_minus_operators[index - 1] == '-':
total_res -= float(item)
else:
total_res = float(item)
print("\033[32;1m[%s]运算结果:\033[0m" % formula, total_res)
return total_res def calc(formula):
'''计算程序主入口, 主要逻辑是先计算拓号里的值,算出来后再算乘除,再算加减'''
parenthesise_flag = True
calc_res = None # 初始化运算结果为None,还没开始运算呢,当然为None啦
while parenthesise_flag:
m = re.search("\([^()]*\)", formula) # 找到最里层的拓号
if m:
# print("先算拓号里的值:",m.group())
sub_res = compute(m.group())
formula = formula.replace(m.group(), str(sub_res))
else:
print('\033[41;1m----没拓号了...---\033[0m') print('\n\n\033[42;1m最终结果:\033[0m', compute(formula))
parenthesise_flag = False # 代表公式里的拓号已经都被剥除啦 if __name__ == '__main__':
# res = calc("1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )")
res = calc(
"1 - 2 * ( (60-30 +(-9-2-5-2*3-5/3-40*4/2-3/5+6*3) * (-9-2-5-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )")