正则之代表边界
^表示以什么开头
$表示以什么结尾
(|)表示或者
小练习:匹配邮箱
import re
email = '1234@qq.com'
# email = 'abcd123@163.com'
# email = 'abcd123哈哈哈@163.com'
result = re.match(r'^\w{4,11}@(?:163|126|qq)\.com$',email)
#(?:163|126|qq)表示不捕获分组里面的值,后面会讲解
print(result)
###这个表达式上面的都可以匹配到
其中的一个运行结果
\b表示匹配单词边界
import re
result = re.match(r'\w+ll\b','hell')
print(result)
单词边界必须是l,运行的结果是
import re
result = re.match(r'\w+ll\b','hell0')
print(result)
结果
因为不是以l结尾的,所以匹配不上,如果想要匹配上,看如下代码
import re
result = re.match(r'\w+ll\b','hell 0')
print(result)
原因:中间有空格,在hell中l是结尾字母,所以符合条件,能匹配上
如果想要匹配整个带有空格的单词,空格也得能够匹配上,像下面这种匹配不上空格的
import re
result = re.match(r'\w+\bll\b','he ll 0')
print(result)
运行结果就是none,因为\w匹配的h,+表示1次或者无数次,所以匹配上的是he,但是e后面的空格没人匹配。如果想要匹配上,就得把空格也匹配了
import re
result = re.match(r'.+\bll\b','he ll 0')
print(result)
因为.表示匹配除了\n的任意字符,+表示1或者无数,所以就可以匹配到he和后面的空格。
注意如果规则前面不加r的话,也匹配不上,因为\b还代表的回车键。需要加上r,消除它的意义。另外,除了单词之外,还有数字也可以
import re
result = re.match(r'.+\b123\b','he 123 0')
print(result)
\B表示匹配非单词边界
import re
result = re.match(r'.+\Bll\B','hell0')
print(result)
e不是单词得边界,l也不是单词的边界,所以可以匹配上
代表分组
|任意一个正则表达式
(ab)将括号作为一个分组
\num 引用分组索引(用法见小练习)
小练习:匹配一个前端成对的标签
#匹配一个成对的标签
import re
s = '<h1>哈哈哈</h1>'
result = re.match(r'<(\w+)>.+</(\1)>',s)
#(\w+)这个表示分组
#(\1)表示这个里面的规则和第一个分组里面的一样
print(result)
如果想取分组里面的值,就需要下面的知识点了
分组可以通过group(index)取到分组里面的内容,index可以是索引,也可以是别名
index表示下标,用法:
#匹配一个成对的标签
import re
s = '<h1>哈哈哈</h1>'
result = re.match(r'<(\w+)>.+</(\1)>',s)
#利用\num来用到分组的匹配
print(result.group(0))
print(result.group(1))
print(result.group(2))
结果
?:表示不取分组里面的值
#匹配一个成对的标签
import re
s = '<h1>哈哈哈</h1>'
result = re.match(r'<(\w+)>.+</(?:\1)>',s)
print(result.group(0))
print(result.group(1))
# print(result.group(2))
?:只能加到第二个分组里面,加到第一个里面会出错,因为第一个分组里面的值都取不到,第二个分组也自然取不到了
(?P< name >)分组别名
如果想要匹配嵌套标签
import re
s = '<h1><li>哈哈哈</li></h1>'
result = re.match(r'<(\w+)><(\w+)>.+</(\2)></(\1)>',s)
print(result)
这样是可以匹配成功的,但是如果标签嵌套很多的话,这样容易迷糊,如果可以给他们起个名字,可能会更好一些,也就是(?P< name>)分组别名,联合下面的知识点一起使用
(?P=name) 引用分组别名
别名的小练习
import re
s = '<h1><li>哈哈哈</li></h1>'
result = re.match(r'<(?P<g1>\w+)><(?P<g2>\w+)>.+</(?P=g2)></(?P=g1)>',s)
print(result)
#<(?P<g1>\w+)>给<h1>起的别名
#</(?P=g1)>引用</h1>的别名
注意P是大写
贪婪模式和非贪婪模式
import re
s = 'liuhhhhh'
result = re.match(r'liuh+',s)
print(result)
把所有满足的都匹配上,就叫做贪婪模式
注意一点+虽然表示一位或者无数,但是如果它跟在h后面,那么只能匹配h,别的不匹配
解决贪婪模式用?
import re
s = 'liuhhhhh'
result = re.match(r'liuh+?',s)
#表示只要匹配一个h就可以了
print(result)
再比如
我只想匹配一对div标签,但是由于贪婪模式就全部匹配上了
要想解决,加?告诉他只要一个div就可以
import re
s = '<div>11</div><div>222</div>'
#我只想匹配<div>11</div>
result = re.match(r'<div>.*?</div>',s)
print(result)
正则默认的就是贪婪模式,?可以解决
再比如一个很明显的例子
出现这个的原因是因为贪婪模式,\w可以匹配数字汉字,+表示1或者无数,就会一直匹配到96,而\d+最少一位就可以,所以最后\d+只能匹配到0,后面的3也是一样的
如果,想匹配到数字,就得关闭前面的贪婪模式,让\d贪婪
#只想要960 13这两个数字
import re
s = '中国有960万平方公里,有13亿人口'
result = re.match(r'\w+?(\d+).*?(\d+).*',s)
print(result.group(1))
print(result.group(2))
这样就可以了
**如果我们只是为了获取这两个数字,可以用下面的知识点,更方便一点
**
search和find all
import re
s = '中国有960万平方公里,有13亿人口'
result = re.search(r'\d+',s)
print(result)
search只返回一个,从左到右开始匹配,匹配到了就返回
import re
s = '中国有960万平方公里,有13亿人口'
result = re.findall(r'\d+',s)
print(result)
findall可以取到所有的数字,而且它返回的是一个列表
sub(替换)和split(分割)
split分割
#以20分割
import re
s = '我今年20岁,身高160'
result = re.split(r'\d+',s,1)
#最后一个参数表示分割的次数
print(result)
sub替换
#以20替换成21
import re
s = '我今年20岁,身高160'
result = re.sub('\d+' , '21',s,1)
#第二个表示要替换后的值
#最后一个参数表示替换一次
print(result)
其中的第二个参数还可以传函数,灵活性强一些
#不管传的年龄是多少,最后都要加1
import re
s = '我今年19岁,身高165'
def add(matched):
age = int(matched.group(1))
#这是通过索引取的
#如果规则有别名的话,也可以通过别名来取
age += 1
return str(age)
result = re.sub(r'(\d+)',add,s,1)
print(result)
通过别名取的话
#不管传的年龄是多少,最后都要加1
import re
s = '我今年19岁,身高165'
def add(matched):
age = int(matched.group('a'))
age += 1
return str(age)
result = re.sub(r'(?P<a>\d+)',add,s,1)
print(result)
运行结果也是一样的
标志位
re.I忽略大小写
import re
s = 'abc'
result = re.match('A',s,re.I)
#大写的i
print(result)
re.S匹配换行
#匹配换行
import re
s = '''abc123
456cde
'''
result = re.match('abc.*456.+',s,re.S)
print(result)
换行符可以匹配出来