文章目录
一、re 正则表达式的定义和作用
正则表达式是一种小型、高度专业化的编程语言。
作用:进行字符串模糊匹配
二、普通字符
绝大部分的字符都是普通字符,比如数字和字母。
普通字符是进行完全匹配。
三、元字符
① . 通配符(除了 \n不能匹配,可以匹配其他任意一个字符)
② ^ 以该字符串开头
③ $ 以该字符串结尾
④ * 重复前一个字符,0~无穷次
⑤ + 重复前一个字符,1~无穷次
⑥ ? 匹配前一个字符,0~1个
⑦ { } 自定义重复范围,例:
{0,} 重复0~无穷次
{1,2} 重复1~2次
{6} 重复6次
注:默认上述元字符均为贪婪匹配,后面加 ?,变为惰性匹配
import re
v1 = re.findall("a..b", "baasbartb")
print(v1) # ['aasb', 'artb']
v2 = re.findall("^ba", "baasbartb")
print(v2) # ['ba']
v3 = re.findall("tb$", "baasbartb")
print(v3) # ['tb']
v4 = re.findall("a*", "baasbartb")
print(v4) # ['', 'aa', '', '', 'a', '', '', '', '']
v5 = re.findall("a+", "baasbartb")
print(v5) # ['aa', 'a']
v6 = re.findall("a?", "baasbartb")
print(v6) # ['', 'a', 'a', '', '', 'a', '', '', '', '']
v7 = re.findall("a{1,2}", "baasbartaaab")
print(v7) # ['aa', 'a', 'aa', 'a']
v8 = re.findall("a{1,2}?", "baasbartaaab")
print(v8) # ['a', 'a', 'a', 'a', 'a', 'a']
⑧ [ ] 字符集,选其中一个元素。字符集内部,除了 \ - ^ ,均为普通字符。其中 - 表示范围,^ 表示非,\ 表示转义字符
⑨ \ 转义字符,作用:
(1)将有意义的元字符变成普通字符
(2)将无意义的普通字符变为有意义的特殊字符
\d 匹配任何十进制数
\D 匹配任何非数字字符
\s 匹配任何空白字符
\S 匹配任何非空白字符
\w 匹配任何字母数字字符和_
\W 匹配任何非字母数字字符和_
import re
v1 = re.findall("[1-9]+", "baas1ba125rtb")
print(v1) # ['1', '125']
v2 = re.findall("[^1-9]+", "baas1ba125rtb")
print(v2) # ['baas', 'ba', 'rtb']
v3 = re.findall("[\d]+", "baas1ba125rtb")
print(v3) # ['1', '125']
v4 = re.findall("[\D]+", "baas1ba125rtb")
print(v4) # ['baas', 'ba', 'rtb']
v5 = re.findall("[\s]+", "baas1b a125rtb")
print(v5) # [' ']
v6 = re.findall("[\S]+", "baas1b a125rtb")
print(v6) # ['baas1b', 'a125rtb']
v7 = re.findall("[\w]+", "baas1b a1_2*5rtb")
print(v7) # ['baas1b', 'a1_2', '5rtb']
v8 = re.findall("[\W]+", "baas1b a1_2*5rtb")
print(v8) # [' ', '*']
\b 匹配以一个特殊字符作为边界,比如空格,&,#等。
import re
#以I开始
v1 = re.findall("\\bI", "Ia am I LoIo")
print(v1) # ['I', 'I']
#以I结束
v2 = re.findall("I\\b", "Ia am I LoIo")
print(v2) # ['I']
注:代码先传给Python解释器进行解释,再传给被调用的re模块。由于\b为Python内置的字符,需要写\\b,或者写r"\b",才能保证传给re模块的代码为\b。 类似的,如下:
import re
v1 = re.findall("\\\\l", "wwf\lgxa")
print(v1) # ['\\l']
v2 = re.findall(r"\\l", "wwf\lgxa") # 传递原生字符串
print(v2) # ['\\l']
⑩ | 或者
import re
v1 = re.search("a(b|c)d", "abdc").group()
print(v1) # abd
⑪ () 分组,内部看成一个整体
注:在findall方法中,会优先匹配分组的字符串,忽略其他部分。
import re
v1 = re.findall("www(baidu)com", "qewwwbaiducomzff")
print(v1) # ['baidu']
v2 = re.search("www(baidu)com", "qewwwbaiducomzff").group()
print(v2) # wwwbaiducom
# 加 ?: 可以取消分组优先
v3 = re.findall("www(?:baidu)com", "qewwwbaiducomzff")
print(v3) # ['wwwbaiducom']
四、re模块常用方法
1、findall
返回所有满足匹配条件的结果,放在列表里。
import re
v1 = re.findall("\d+", "wded123fw54")
print(v1) # ['123', '54']
2、search
只返回第一个查到结果,构成的对象。可通过group方法得到匹配的字符串。没查到结果,返回None
v2 = re.search("\d+", "wded123fw54").group()
print(v2) # 123
v3 = re.search("\d{5}}", "wded123fw54")
print(v3) # None
3、match
类似search,但只从字符串开头匹配。
v = re.match("\d+", "wded123fw54")
print(v) # None
4、split
分割
v1 = re.split('\d+',"wded123fw54")
print(v1) # ['wded', 'fw', '']
v2 = re.split('\d+',"wded123fw54a",1)
print(v2) # ['wded', 'fw54a']
5、sub
替换
v1 = re.sub('\d+',"A","wded123fw54")
print(v1) # wdedAfwA
v2 = re.sub('\d+',"A","wded123fw54",1)
print(v2) # wdedAfw54
6、subn
返回一个元组,(匹配结果,匹配个数)
v1 = re.subn('\d+',"A","wded123fw54")
print(v1) # ('wdedAfwA', 2)
7、compile
编译
co = re.compile("\d+")
v = co.findall("wded123fw54")
print(v) # ['123', '54']
8、finditer
类似findall方法,但是返回的是一个迭代器
v1 = re.finditer("\d+", "wded123fw54")
print(v1) # <callable_iterator object at 0x000002676E7004C0>
print(v1.__next__().group()) # 123
print(v1.__next__().group()) # 54
五、字符串匹配的其他用法
v4 = re.search("(?P<name>[a-z]+)(?P<age>\d+)", "wded123fw54").group("name")
print(v4) # wded
v5 = re.search("(?P<name>[a-z]+)(?P<age>\d+)", "wded123fw54").group("age")
print(v5) # 123
六、小练习:计算器
用户输入一个类似这样 3*( 4+ 50 )-(( 100 + 40 )5/2- 32* 2/4+9)*((( 3 + 4)-4)-4) 这样的表达式,然后自己动手写代码解析其中的表达式,实现加减乘除。
import re
def multiply_divide(s): # 最小乘除法计算单元
ret = float(s.split('*')[0]) * float(s.split('*')[1]) if '*' in s else float(s.split('/')[0]) / float(s.split('/')[1])
return ret
def remove_md(s): # 消除s中所有的乘除法
if '*' not in s and '/' not in s: # s中没有乘除法,直接返回
return s
else: # s中有乘除法,消除左边第一个乘除法算式
k = re.search(r'-?[\d.]+[*/]-?[\d.]+', s).group()
s = s.replace(k, '+' + str(multiply_divide(k))) if len(re.findall(r'-', k))%2 == 0 else s.replace(k, str(multiply_divide(k)))
# 遇到例如 1+2*3 的情况,2*3的计算结果前面需要加“+”,即'+' + str(multiply_divide(k)),不然输出为16
return remove_md(s)
def add_sub(s): # 从左到右计算加减法
while re.findall("[+-]{2}", s):
s = s.replace("++", "+")
s = s.replace("--", "+")
s = s.replace("+-", "-")
s = s.replace("-+", "-")
l = re.findall('[\d.]+|-|\+', s)
if l[0] == '-': # 首元为负号,则合并第一二个元素为一个负数
l[0] = l[0] + l[1]
del l[1]
sum = float(l[0])
for i in range(1, len(l), 2):
if l[i] == '+':
sum += float(l[i + 1])
else:
sum -= float(l[i + 1])
return sum
def basic_operation(s):
s = s.replace(' ', '')
return add_sub(remove_md(s))
def calculate(expression): # 处理含有小括号的算式
if not re.search(r'\([^()]+\)', expression): # 匹配最里面的括号,如果没有的话,直接进行运算,得出结果
return basic_operation(expression)
k = re.search(r'\([^()]+\)', expression).group() # 将匹配到的括号里面的表达式交给basic_operation处理后重新拼接成字符串递归处理
expression = expression.replace(k, str(basic_operation(k[1:len(k) - 1])))
return calculate(expression)
s = '1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )'
print('用eval计算出来的值为:{}\n计算器计算出来的值为:{}'.format(eval(s), calculate(s)))
# >>> 用eval计算出来的值为:2776672.6952380957
# >>> 计算器计算出来的值为:2776672.6952380957