一正则表达式的引入
#需求:封装一个功能,判断用户输入的手机号码是否合法?
def checkPhone(phone):
if len(phone) != 11:
print('手机号码不是十一位')
return
if phone[0] != '1':
print('手机号码开头不是1')
return
if not phone.isdigit():
print('手机号码不是全部是数字')
return
print('该手机号码是正确的')
checkPhone(112233)
使用正则表达式:
import re#需要引用re模块
result = re.search("^1\d{10}$", "12345678901")#^ 表示从什么开始(^1表示从1开始) \d表示0~9之间的数字 {10}表示出现次数为10位$结束
if result:
print('手机号码合法')
else:
print('手机号码不合法')
输出:
手机号码合法
二正则表达式的介绍和查找
正则表达式:是一个特殊的字符序列,通常用来检索,替换那些符合某个模式(规则)的文本
在python中需要通过正则表达式对字符串进行匹配的时候,可以使用re模块。re模块使python语言拥有全部的正则表达式功能。
应用场景:
爬虫
验证手机号码,身份证号码邮箱等
数据分析的数据清洗或者整理
\d 表示0~9之间的任意数字
+ 表示可以出现一次或者多次
正则表达式中使用 \ 作为转义字符,如果需要匹配文本中的字符 \ ,则使用编程语言表示的正则表达式里需要4个反斜杠 \ :前两个和后两个分别用于在编程语言里转义成反斜杠,转换成反斜杠后再在正则表达式里转义成一个反斜杠。
(1)正则表达式的分组
#匹配0-100数字
n = '100'
result = re.match(r'[1-9]?\d?$|100$', n)#| 表示或者
print(result)#<re.Match object; span=(0, 3), match='100'>
#验证邮箱 163 126 qq
email = '1234568@qq.com'
result = re.match(r'\w{5,20}@(163|126|qq)\.(com|cn)$', email)#(word|word|word) 表示或者 [abc]表示一个字母而不是一个单词
print(result)#<re.Match object; span=(0, 14), match='1234568@qq.com'>
result.group()获取组中匹配内容
相关方法:
起名方式:(?P<名字>正则) (?P=名字)
不需要引用分组内容:
msg = '<html><h1>abc</h1>'
msg1 = '<h1>hello</h1>'
result = re.match(r'<[0-9a-zA-Z]+>(.+)</[0-9a-zA-Z]+', msg)
print(result)# 输出:<re.Match object; span=(0, 17), match='<html><h1>abc</h1'>
print(result.group(1))#输出:<h1>abc
需要引用分组匹配的内容
1、number \number 引用第number组的数据
msg = '<html><h1>abc</h1></html>'
result = re.match(r'<([0-9a-zA-Z]+)><([0-9a-zA-Z]+)>(.+)</\2></\1>$', msg)
print(result)#<re.Match object; span=(0, 25), match='<html><h1>abc</h1></html>'>
2、?P<名字>
msg = '<html><h1>abc</h1></html>'
result = re.match(r'<(?P<name1>\w+)><(?P<name2>\w+)>(.+)</(?P=name2)></(?P=name1)>', msg)
print(result)#<re.Match object; span=(0, 25), match='<html><h1>abc</h1></html>'>
print(result.group(1))#html
(2)正则表达式查找常用的函数
re.match(匹配字符串是否以指定的正则内容开头)
re.search(扫描整个字符串,找到第一个匹配)
re.findall(扫描整个字符串,找到所有的匹配)
re.finditer(扫描整个字符串,找到所有匹配的,并返回一个可迭代对象)
re.sub(正则表达式,‘新内容’, string)(扫描整个字符串,新内容替换正则内容指定的内容)
re.split(在字符串中搜素,对指定的内容进行分割)
re.match(pattern, string, flags=0)
匹配成功返回对象,匹配失败返回None
pattern:匹配的正则表达式
string:要匹配(验证)的字符串
flags: 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多 行匹配等
可以使用group(num)函数来获取匹配的表达式, group()用来提出分组截获的字符串
import re
print(re.match("\d+", "123asd"))#验证成功后返回的对象<re.Match object; span=(0, 3), match='123'>
print(re.match("\d+", "hello12345"))
result1 = re.match(r'H', 'Hello')
result2 = re.match(r'e', 'Hello')
print(result1.group(0))#'H'p匹配到的元素
print(result1.span())#(0, 1)匹配到的元素所在位置
print(result2)
输出:
<re.Match object; span=(0, 3), match='123'>
None
H
(0, 1)
None
re.search(pattern, string, flags = 0)
匹配成功返回对象,匹配失败返回None
import re
print(re.search('\d+', '123asd98'))#<re.Match object; span=(0, 3), match='123'>
print(re.search('\d+', 'hello12345'))
result1 = re.search(r'He', 'Hello')
result2 = re.search(r'lo', 'Hello')
print(result1.group(0))
print(result1.span())
print(result2.group(0))
print(result2.span())
输出:
<re.Match object; span=(0, 3), match='123'>
<re.Match object; span=(5, 10), match='12345'>
He
(0, 2)
lo
(3, 5)
re.findall(pattern, string, flags = 0)
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
注意: match 和 search 是匹配一次 findall 匹配所有。
ret = re.findall('\d+', 'he23ll34')
print(ret)
ret = re.match('\d+', 'he23ll34')
print(ret)
ret = re.search('\d+', 'he23ll34')
print(ret)
msg = 'abcd7v jkfd8hdf00'
result = re.search('[a-z][0-9][a-z]', msg)# 只要有1个匹配的后面就不会继续检索
print(result.group())#d7v
result = re.findall('[a-z][0-9][a-z]', msg)# 匹配整个字符串,一直到结尾
print(result)#['d7v', 'd8h']
输出:
['23', '34']
None
<re.Match object; span=(2, 4), match='23'>
d7v
['d7v', 'd8h']
注意:
findall方法匹配时,如果匹配规则里有分组,则只匹配分组数据
ret = re.findall(r'\w+@(qq|126|163)\.com', '123@qq.com;aa@163.com;bb@126.com')
print(ret)#['qq', '163', '126']
如果正则表达式里存在多个分组,则会把多个分组匹配成元组
ret = re.findall(r'\w+@(qq|126|163)(\.com)', '123@qq.com;aa@163.com;bb@126.com')
print(ret)#[('qq', '.com'), ('163', '.com'), ('126', '.com')]
如果想要让findall匹配所有的内容,而不仅仅只是匹配正则表达式里的分组,可以使用 ?:来将分组标记为非捕获分组。
ret = re.findall(r'\w+@(?:qq|126|163)(\.com)', '123@qq.com;aa@163.com;bb@126.com')
print(ret)#['.com', '.com', '.com']
ret = re.findall(r'\w+@(?:qq|126|163)\.com', '123@qq.com;aa@163.com;bb@126.com')
print(ret)#['123@qq.com', 'aa@163.com', 'bb@126.com']
re.finditer(pattern, string, flags = 0)
和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。
ret = re.finditer(r'\d+', 'he123456')# 得到的结果是一个可迭代对象
for x in ret:# 遍历 ret 取出里面的每一项匹配
print(x.group(), x.span())#123456 (2, 8)# 匹配对象里的group保存了匹配的结果
ret = re.finditer(r'\d', 'he123456')
for x in ret:
print(x.group(), x.span())
输出:
123456 (2, 8)
1 (2, 3)
2 (3, 4)
3 (4, 5)
4 (5, 6)
5 (6, 7)
6 (7, 8)
re.sub(pattern, repl, string, count, flags)
result = re.sub(r'\d+', '90', 'java:99,python:100')
print(result)#java:90,python:90
def func(temp):
num = temp.group()
num1 = int(num) + 1
return str(num1)
result = re.sub(r'\d+', func, 'java:99,python:100')
print(result)#java:100,python:101
re.split(pattern, string, maxsplit, flags)
将分割的内容保存到列表中
result = re.split(r'[,:]', 'java:99,python:100')
print(result)#['java', '99', 'python', '100']
三re.Match类
相关属性:
pos 搜索的开始位置
endpos 搜索的结束位置
string 搜索的字符串
re 当前使用的正则表达式的对象
lastindex 最后匹配的组索引
lastgroup 最后匹配的组名
group(index=0) 某个分组的匹配结果。如果index等于0,便是匹配整个正则表达式
groups() 所有分组的匹配结果,每个分组的结果组成一个列表返回
groupdict() 返回组名作为key,每个分组的匹配结果座位value的字典
start([group]) 获取组的开始位置
end([group]) 获取组的结束位置
span([group]) 获取组的开始和结束位置
expand(template) 使用组的匹配结果来替换模板template中的内容,并把替换后的字符串返回
ret = re.search('(abc)+', 'xxxabcabcabcdef')
print(ret.pos) # 搜索开始的位置,默认是0
print(ret.endpos)# 搜索结束的位置,默认是字符串的长度
print(ret.group(0))# abcabcabc 匹配整个表达式
print(ret.group(1))# abc 第一次匹配到的结果
print(ret.span())#(3, 12) 开始和结束位置
print(ret.groups())# 表示当正则表达式里有多个分组时,多个分组的匹配结果
输出:
0
15
abcabcabc
abc
(3, 12)
('abc',)
四re.compile方法的使用
我们在使用正则表达式时,可以直接调用re 模块的 match,search,findall等方法,传入指定的正则表达式。同时,也可以调用re.compile方法,生成一个正则表达式对象,再调用这个正则表达式对象的相关方法实现匹配
msg = '娜扎热巴黛丝佟丽娅'
pattern = re.compile('佟丽娅')
result = pattern.search(msg)
print(result)
输出:
<re.Match object; span=(6, 9), match='佟丽娅'>
五 正则表达式的字符和特殊字符
\b 匹配一个单词边界也就是指单词和空格间的位置
msg = 'aa*py ab.txt bb.py kk.png uu.py apyb.txt'
result = re.findall(r'\w+\.py\b', msg)# .前面的\表示转义
print(result)#['bb.py', 'uu.py']
\B 非单词边界
\d 匹配数字,0~9之间任意的数字,等同于[0 ~9]
print(re.search('he\dllo', 'he8llo'))#<re.Match object; span=(0, 6), match='he8llo'>
print(re.search('he[0-9]llo', 'he9llo'))#<re.Match object; span=(0, 6), match='he9llo'>
print(re.search('he\dllo', 'heallo'))#None
\D 匹配非数字字符,可以理解为对\d取反 等同于[^ 0 – 9 ]
print(re.search('hello\D', 'hello1'))#None
print(re.search('hello\D', 'hello_'))#<re.Match object; span=(0, 6), match='hello_'>
print(re.search('hello\D', 'helloS'))#<re.Match object; span=(0, 6), match='helloS'>
\w 匹配数字,字母,下划线 等同于 [0-9a-zA-Z_ ]
print(re.search('hello\w', 'hello!'))#None
print(re.search('hello\w', 'hello9'))#<re.Match object; span=(0, 6), match='hello9'>
print(re.search('hello\w', 'hellowe'))#<re.Match object; span=(0, 6), match='hellow'> 只匹配一个
print(re.search('hello\w', 'helloD'))#<re.Match object; span=(0, 6), match='helloD'>
print(re.search('hello\w', 'hello_'))#<re.Match object; span=(0, 6), match='hello_'>
\W 匹配非数字,字母,下划线 等同于 [^0-9a-zA-Z_ ]
print(re.search('hello\W', 'hello!'))#<re.Match object; span=(0, 6), match='hello!'>
print(re.search('hell\W', 'hello9'))#None
\s 匹配任意的空白字符 (空格,回车,换行,制表符,换页)等同于[ \r \n \t \f]
\S 匹配任意的非空白字符 (空格,回车,换行,制表符,换页)等同于[ ^ \r \n \t \f]
#\t 是空格
print(re.search('he\sllo', 'he\tllo'))#<re.Match object; span=(0, 6), match='he\tllo'>
print(re.search('he\Sllo', 'he\tllo'))#None
^ 开头
–表示一个区间
. 表示匹配除了换行符之外的任意字符
$ 表示匹配到结尾
* 用于将前面模式匹配0次或者多次(贪婪模式,即尽可能多的匹配)》=0
+ 用于将前面的模式匹配1次或多次(贪婪模式)>=1
? 用于将前面的模式匹配0次或1次(贪婪模式)0,1
{m} 用于验证将前面的模式匹配m次
{m,} 用于验证将前面的模式匹配m次或多次 >=m
{m,n} 用于验证将前面的模式匹配大于等于m次且小于等于n次
(word|word|word) 表示或者 | 表示或者
[abc]表示一个字母而不是一个单词
[ ] 表示范围,用于表示一组字符,如果^ 是第一个字符,则表示的是一个补集。比如 [0-9]表示所有数字 [^ 0-9]表示除了数字外的字符
*? +? ??是 * + ?的非贪婪模式(尽可能少的匹配)
六 正则表达式的模式修饰符
用来修饰正则表达式,是一个可选参数
re.S 可以使正则表达式中的 ’ . ’ 匹配到换行符
import re
print(re.search('shenzhen.', 'shenzhen9'))#<re.Match object; span=(0, 9), match='shenzhen9'>
print(re.search('shenzhen.', 'shenzhen\n'))#None
print(re.search('shenzhen.', 'shenzhen\n', re.S))#<re.Match object; span=(0, 9), match='shenzhen\n'>
re.I 表示正则表达式在匹配后面的内容时忽略大小写。
print(re.search('shenzhen[a-z]', 'shenzhenM'))#None
print(re.search('shenzhen[a-z]', 'shenzhenM', re.I))#<re.Match object; span=(0, 9), match='shenzhenM'>
re.M 多行匹配,影响 ^ 和 $ ,每个换行都认为是一个结尾
\w+$ 表示匹配以一个或者多个字母结尾
print(re.findall(r'\w+$', 'i am boy\n you are girl\n he is man\n', re.M))#['boy', 'girl', 'man']
print(re.findall(r'\w+$', 'i am boy\n you are girl\n he is man\n'))#['man']
七 正则表达式贪婪与非贪婪
python里的数量词默认是贪婪的,总是尝试匹配尽可能多的字符
在非贪婪里则相反,总是尝试匹配尽可能少的字符
在“ * ” “ ?” “+” “{m,n}”后面加上?,是贪婪变成非贪婪
#贪婪模式
msg = 'abc123abc'
result = re.match(r'abc(\d+)', msg)
print(result)#输出:<re.Match object; span=(0, 6), match='abc123'>
#非贪婪模式
msg1 = 'abc123abc'
result = re.match(r'abc(\d+?)', msg1)
print(result)#输出:<re.Match object; span=(0, 4), match='abc1'>