1.正则表达式
正则表达式面向什么样的问题?
1.判断一个字符串是否匹配给定的格式(判断是不是邮箱或者电话号码)
2,从一个字符串里面根据指定规则提取信息(抓取页面中的链接或者其它信息)
2. re模块
正则表达式写出来后需要使用
那么需要使用re模块进行使用,提取及验证等操作
re模块为内置模块
使用时需要导包 ----- import re
常用方法分为:findall, match, search
修饰符(可选标志)
修饰符 | 描述 |
---|---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 多行匹配,影响 ^ 和 $ |
re.S | 使 . 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 |
接下来具体学习一下
# ====== findall =======
# re.finall(目标数据,目标字符串)
# 在目标字符串中找出所有符合目标数据的数据,符合条件的数据放入列表中
# 没有就返回空列表
#
import re
data = 'python学习快乐 哈哈哈 python1223334python'
filter_data = re.findall('python', data) # 匹配 python
print(filter_data) # ['python', 'python', 'python']
# ====== match =======
# re.match(pattern, string, flags=0)
# pattern 匹配的正则表达式
# string 要匹配的字符串
# flags 标志符指定,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
# 必须从字符串开头匹配!
# match方法尝试从字符串的起始位置匹配一个模式,
# 如果不是起始位置匹配成功的话,match()就返回none
# 返回值为对象
# group:查看匹配字符
# span:查看匹配数据的索引取值区间
import re
data = 'python学习快乐 哈哈哈 python1223334python'
# 使用方法1:直接匹配,返回值是一个对象(开头开始匹配能匹配到)
filter_data = re.match('python', data)
print(filter_data) # <re.Match object; span=(0, 6), match='python'>
# group:查看匹配字符
print(filter_data.group()) # python
# span:查看匹配数据的索引取值区间
print(filter_data.span()) # (0, 6)
"""
如果开头匹配不到,返回为空
filter_data = re.match('122', data)
print(filter_data) # None ---空
"""
------------ search --------------------
re.search(pattern, string, flags=0)
扫描整个字符串并返回第一个成功的匹配。(找不到返回为空)
# pattern 匹配的正则表达式
# string 要匹配的字符串
# flags 标志符指定,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
# group:查看匹配字符
# span:查看匹配数据的索引取值区间
import re
data = 'python学习快乐 哈哈哈 python1223334python1'
filter_data = re.search('python1', data)
print(filter_data) # <re.Match object; span=(15, 22), match='python1'>
print(filter_data.group()) # python1
print(filter_data.span()) # (15, 22)
3.元字符
元字符就是具有特殊含义的字符
常规
字符 | 解释 |
---|---|
0-9 | 0到9范围 |
a-z | a到z范围 |
A-Z | A到Z范围 |
单字符匹配
字符 | 解释 |
---|---|
. | 匹配任意 一个 字符(除了\n) |
[] | 匹配[]中列举的字符 |
\d | 匹配数字(0-9) |
\D | 匹配非数字(不是数字) |
\s | 匹配空白(空格,tab键) |
\S | 匹配非空白(非转义字符) |
\w | 匹配单词字符(0-9,a-z, A-Z, 中文) |
\W | 匹配非单词字符(包括空格) |
数量元字符
字符 | 解释 |
---|---|
* | 匹配前一个字符出现0次或者无限次,即可有可无 |
+ | 匹配前一个字符出现一次或无限次,即必须出现1次 |
? | 匹配前一个字符出现一次或零次,要么有一次,要么没有 |
{m} | 匹配前一个字符出现m次 |
{m,} | 匹配前一个字符至少出现m次 |
{m,n} | 匹配前一个字符出现m到n次(出现次数范围) |
边界元字符
字符 | 解释 |
---|---|
^ | 匹配字符串开头(以什么开头) |
$ | 匹配字符串结尾(以什么结尾) |
\b | 匹配一个单词的边界 |
\B | 匹配非单词的边界 |
注:取消字符串转义,以空格为边界
分组匹配
字符 | 解释 |
---|---|
| | 匹配左右任意一个表达式 |
(规则) | 将括号中的字符作为一个分组,提取符合规则的数据 |
贪婪模式与非贪婪模式
. 匹配任意 一个 字符(除了\n)
* 匹配前一个字符出现0次或者无限次,即可有可无
? 匹配前一个字符出现一次或零次,要么有一次,要么没有
正则默认都是贪婪模式去匹配数据,就是尽可能多的匹配符合要求的数据
.*
import re
data = '<快乐每一天> <---- 张三>'
# 贪婪模式
filter_data1 = re.findall('<.*>', data)
print(filter_data1) # ['<快乐每一天> <---- 张三>']
非贪婪模式就是始终找最短的匹配
.*?
# 非贪婪模式 ----- ?
filter_data2 = re.findall('<.*?>', data)
print(filter_data2) # ['<快乐每一天>', '<---- 张三>']
4.实践
匹配邮箱:
首先邮箱特征 *********@***.com
第一部分:********* --- 多个数字,英文字母组成 -- 数量不确定
第二部分: *** --- 多个数字,英文字母组成
正则书写:[0-9a-zA-Z]+@[0-9a-zA-Z]+.com
# 限制长度:[0-9a-zA-Z]{6,10}@[0-9a-zA-Z]{2,4}.com
import re
data = '290876583@qq.com不是他的邮箱, 他的邮箱是:290876583@163.com'
filter_list = re.findall(r'[0-9a-zA-Z]+@[0-9a-zA-Z]+.com', data)
print(filter_list) # ['290876583@qq.com', '290876583@163.com']
匹配手机电话号码
# 手机号都为11位,所以必须限定匹配的数字的位数,通过$来限定以9位数字结尾,
# 又因为手机号都以1开头,所以通过^1限定以1开头,
# 然后手机号第二位貌似只有3,5,6,7,8,这几个数字,所以通过[3,5,6,7,8]来匹配其中的任一数字,
正则书写: ^1[35678]\d{9}$
import re
data = '15613145200'
# ^1[35678]\d{9}$
filter_list = re.findall(r'^1[35678]\d{9}$', data)
print(filter_list) # ['15613145200']
=======================================================
import re
data = '11613145200是你的号码吗?不是,我的是:15613145200,13789406736'
# 1[35678]\d{9} ---- 匹配多组
filter_list = re.findall(r'(1[35678]\d{9})', data)
print(filter_list) # ['15613145200', '13789406736']
=======================================================
# 提取数据
import re
data = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
<li class="qwe">学生:张三</li>
<li class="haha">学生:李四</li>
<li class="hasd">学生:王二</li>
<li class="haqw">学生:麻子</li>
<li class="hax">学生:快乐</li>
<li class="haww">学生:伤心</li>
<li class="hazx">学生:愤怒</li>
<li class="hwe">学生:喜欢</li>
</ul>
</body>
</html>
"""
# 目的:提取所有学生姓名
# 都在 <li class="qwe">学生:张三</li>
# 规则1:class="" 里面内容不同 --- 不需要数据 ---但是需要定义规则去统一
# class=".*?"
# 规则2:学生:后面是学生姓名,并且需要提取
# 学生:(.*?)
# 正则书写:<li class=".*?">学生:(.*?)</li>
filter_list = re.findall(r'<li class=".*?">学生:(.*?)</li>', data)
print(filter_list) # ['张三', '李四', '王二', '麻子', '快乐', '伤心', '愤怒', '喜欢']