re模块 正则表达式
一.字符组
正则 | 带匹配字符 | 匹配结果 | 说明 |
[0123456789] |
8 | True |
在一个字符组里枚举合法的所有字符,字符组里的任意一个字符 |
[0123456789] |
a |
False |
由于字符组中没有"a"字符,所以不能匹配 |
[0-9] |
7 |
True |
也可以用-表示范围,[0-9]就和[0123456789]是一个意思 |
[a-z] |
s |
True |
同样的如果要匹配所有的小写字母,直接用[a-z]就可以表示 |
[A-Z] |
B |
True |
[A-Z]就表示所有的大写字母 |
[0-9a-fA-F] |
e |
e |
可以匹配数字,大小写形式的a~f,用来验证十六进制字符 |
二.字符
元字符 | 匹配内容 |
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母或数字或下划线 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
\n | 匹配一个换行符 |
\t | 匹配一个制表符 |
\b | 匹配一个单词的结尾 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结尾 |
\W | 匹配非字母或数字或下划线 |
\D | 匹配非数字 |
\S | 匹配非空白符 |
a|b | 匹配字符a或字符b |
() | 匹配括号内的表达式,也表示一个组 |
[...] | 匹配字符组中的字符 |
[^....] 匹配除了字符组中字符的所有字符
三 量词
量词 | 用法说明 |
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或者一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
案例:.^$
正则 | 带匹配字符 | 匹配结果 |
海. | 海燕海娇海东 | 海燕海娇海东 |
^海. | 海燕海娇海东 | 海燕 |
海.$ | 海燕海娇海东 | 海东 |
案例:*+?{}
正则 | 带匹配字符 | 匹配结果 | 说明 |
李.? | 李杰和李莲英和李二棍子 |
李杰 李莲 李二 |
?表示重复零次或一次,即只匹配‘李’后面一个任意字符 |
李.* | 李杰和李莲英和李二棍子 | 李杰和李莲英和李二棍子 | *表示重复零次或多次,即匹配‘李’后面0或多个任意字符 |
李.+ | 李杰和李莲英和李二棍子 | 李杰和李莲英和李二棍子 | +表示重复一次或多次,即只匹配‘李’后面1个或多个任意字符 |
李.{1,2} | 李杰和李莲英和李二棍子 |
李杰和 李莲英 李二棍 |
{1,2}匹配1到2次任意字符 |
注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
正则 | 带匹配字符 | 匹配结果 | 说明 |
李.*? | 李杰和李莲英和李二棍子 | 李李李 | 惰性匹配 |
案例:字符集[] [^]
正则 | 带匹配字符 | 匹配结果 | 说明 |
李[李莲英二棍子]* | 李杰和李莲英和李二棍子 | 李杰李莲英李二棍子 | 表示匹配‘李’字后面[杰莲英二棍子]的字符任意次 |
李[^和]* | 李杰和李莲英和李二棍子 | 李杰李莲英李二棍子 | 表示匹配一个不是‘和’的任意次 |
[\d] | 456bdha3 | 4563 | 表示匹配任意一个数字,匹配到四个结果 |
[\d]+ | 456bdha3 | 4563 | 表示匹配任意个数字,匹配到2个结果 |
案例:分组()与或 | [^]
身份证号是一个长度为15或18个字符的字符串,如果是15位则全部由数字组成,
首位不能为0,如果是18位,则前17位全部是数字,末位可能是数字或x,下面我们尝试用正则来表示:
正则 | 带匹配字符 | 匹配结果 | 说明 |
^[1-9]\d{13,16}[0-9x]$ | 110101198001017032 | 110101198001017032 | 表示可以匹配一个正确的身份证号 |
^[1-9]\d{13,16}[0-9x]$ | 1101011980010170 | 1101011980010170 |
表示也可以匹配这串数字,但这并不是一个正确的身份证号码,它是一个16位的数字 |
^[1-9]\d{14}(\d{2}[0-9x])?$ | 1101011980010170 | False |
现在不会匹配错误的身份证号了 |
^([1-9]\d{16}[0-9x]|[1-9]\d{14})$ | 110105199812067023 | 110105199812067023 |
表示先匹配[1-9]\d{16}[0-9x]如果没有匹配上就匹配[1-9]\d{14} |
#贪婪匹配
贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配
正则 | 带匹配字符 | 匹配结果 | 说明 |
<.*> | <script>...<script> | <script>...<script> | 默认为贪婪匹配模式,会匹配尽量长的字符串 |
<.*?> | r'\d' | <script> <script> |
加上?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串 |
几个常用的非贪婪匹配
*?重复任意次,但尽可能少重复
+?重复1次或更多次,但尽可能少重复
??重复0次或1次,但尽可能少重复
{n,m}?重复n到m次,但尽可能少重复
{n,}?重复n次以上,但尽可能少重复
re模块使用
三个必须掌握的方法
-
findall
-
search
-
import re
"""
findall
search
match
"""
# res = re.findall('[a-z]+','eva egon jason')
# # findall('正则表达式','带匹配的字符串')
# print(res)
# 找出字符串中符合正则表达式全部内容 并且返回的是一个列表,列表中的元素就是正则匹配到的结果
# res = re.search('a','eva egon jason')
# print(res) # search不会给你直接返回匹配到的结果 而是给你返回一个对象
# print(res.group()) # 必须调用group才能看到匹配到的结果
"""
注意:
1.search只会依据正则查一次 只要查到了结果 就不会再往后查找
2.当查找的结果不存在的情况下 调用group直接报错
"""
# res1 = re.search('a','eva egon jason')
# # search('正则表达式','带匹配的字符串')
# if res1:
# print(res1.group())
# res = re.match('a','eva egon jason')
# print(res)
# print(res.group())
"""
注意:
1.match只会匹配字符串的开头部分
2.当字符串的开头不符合匹配规则的情况下 返回的也是None 调用group也会报错
"""
其他方法
ret = re.split('[ab]', 'abcd') # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
print(ret) # ['', '', 'cd']
ret = re.sub('\d', 'H', 'eva3egon4yuan4', 1) # 将数字替换成'H',参数1表示只替换1个
print(ret) # evaHegon4yuan4
ret = re.subn('\d', 'H', 'eva3egon4yuan4') # 将数字替换成'H',返回元组(替换的结果,替换了多少次)
print(ret)
obj = re.compile('\d{3}') #将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字
ret = obj.search('abc123eeee') #正则表达式对象调用search,参数为待匹配的字符串
print(ret.group()) #结果 : 123
import re
ret = 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]) #查看剩余的左右结果
扩展:分组优先机制
import re
res = re.search('^[1-9]\d{14}(\d{2}[0-9x])?$',110105199812067023)
print(res.group())
print(res.group(1)) # 获取正则表达式括号阔起来分组的内容
print(res.group(2)) # search与match均支持获取分组内容的操作 跟正则无关是python机制
# 而针对findall它没有group取值的方法,所以它默认就是分组优先获取的结果
ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com')
print(ret) # ['oldboy'] 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可
ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com') # ?:取消分组优先
补充
import re
ret = re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>")
#还可以在分组中利用?<name>的形式给分组起名字
#获取的匹配结果可以直接用group('名字')拿到对应的值
print(ret.group('tag_name')) #结果 :h1
print(ret.group()) #结果 :<h1>hello</h1>
"""
注意?P=tag_name相当于引用之前正则表达式,并且匹配到的值必须和前面的正则表达式一模一样
"""
# 匹配整数
ret=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']
print(ret) # ['www.oldboy.com']
补充;
'''
今日内容
1 正则表达式
2 re 模块
'''
# 一正则表达式
'''
正则表达式与re模块的关系
1.正则表达式是一门独立的技术,任何语言均可使用
2.python中想要使用正则表达式需要通过re模块
3.所有的编程语言都可以使用正则
正则就是用来筛选字符串中的特定的内容的
正则的应用场景有哪些:
1.爬虫
2.数据分析
为什么要使用正则:那么来举一个例子来说明一下
一个手机号有无正则校验的区别
纯python代码校验
while True:
phone_number = input('please input your phone number : ')
if len(phone_number) == 11 \
and phone_number.isdigit()\
and (phone_number.startswith('13') \
or phone_number.startswith('14') \
or phone_number.startswith('15') \
or phone_number.startswith('18')):
print('是合法的手机号码')
else:
print('不是合法的手机号码')
正则表达式校验
import re
phone_number = input('please input your phone number : ')
if re.match('^(13|14|15|18)[0-9]{9}$',phone_number):
print('是合法的手机号码')
else:
print('不是合法的手机号码')
正则在所有语言中都可以使用 不是python独有的
匹配大段文本中特定的字符
想要匹配具体的内容,可以直接写完整的内容,不需要写正则
有一些注意点:
1.字符组[]
一个字符串里面的表达式都是或的关系
2.^与$符连用,会精准限制匹配的内容
俩者之间写什么,匹配的字符串就必须是什么
多一个也不行少一个也不行
3.abc|ab 一定要将长的放在前面
4.^直接写在外面,会限制字符串的开头
[^]除了[]写的字符,其他都要
5.正则在匹配的时候默认都是贪婪匹配(尽量匹配多的)
你可以通过在量词后面加上一个?就可以将贪婪匹配变成非贪婪匹配(惰性匹配)
6.量词必须跟在正则符号的后面,量词只能够限制紧挨着它的那一个正则符号
7.分组:当多个正则符号需要重复多次的时候或者当做一个整体进行其他操作,
那么可以分组的形式,分组在正则的语法中就是()
'''