正则表达式
1. 作用
表达对字符串数据的 匹配 过滤 提取 逻辑的表达式(字符串)
2. 简单使用
Regular Expression re
匹配结果对象 = re.match(正则, 数据)
从头开始匹配 如果某一个匹配失败 整体就失败了
如果匹配成功 返回匹配结果对象
如果匹配失败 返回None
获取匹配结果
匹配结果对象.group()
"墙裂"建议: 正则一律加上r字符
3. 匹配一个字符
3.1 .点字符
匹配除\n字符之外的任意一个字符
如果需要.匹配 .点字符本身的含义 而不是任意字符 需要对.进行转义 \.
re.match(r"python.", "python2").group()
re.match(r"python.", "pythonX").group()
re.match(r"python.", "python\n").group()
re.match(r"python.org", "pythonXorg").group()
re.match(r"python\.org", "python.org").group()
re.match(r"python\.org", "pythonXorg").group() # 失败
3.2 []
[字符] 匹配其中任意一个字符
[-] 匹配范围内的一个任意字符
[0-9] 匹配一个任意数字字符
[A-Z] 匹配一个任意大写字母
[a-z] 小写字母
re.match(r"python[23]", "python3").group()
re.match(r"python[23]", "pythonX").group()
re.match(r"python[0123456789]", "python3").group()
re.match(r"python[0-9]", "python2").group()
re.match(r"python[0-9]", "python3").group()
re.match(r"python[0-9]", "pythonX").group() # 失败
[^] 取反- 表示禁止匹配 集合内的任意一个字符
re.match(r"python[^0-9]", "python2").group() # 失败
re.match(r"python[^0-9]", "pythonX").group()
3.3 \d数字digit字符
\D非数字字符
re.match(r"python[0-9]", "python1").group()
re.match(r"python\d", "python1").group()
re.match(r"python\d", "pythonX").group() # 失败
re.match(r"python\D", "python9").group() # 失败
e.match(r"python\D", "python$").group()
\w 单词word字符 [0-9a-zA-Z_]
\W 非单词字符 [^0-9a-zA-Z_]
re.match(r"python\w", "python1").group()
re.match(r"python\w", "pythona").group()
re.match(r"python\w", "python_").group()
re.match(r"python\w", "python%").group() # 失败
re.match(r"python\W", "python%").group() # 失败
\s space 空白字符 等价于 [ \r\n\t\v\f\r]
\S 非空白字符 等价于 [^ \r\n\t\v\f]
re.match(r"python\s", "python cpp").group()
re.match(r"python\s", "python\tcpp").group()
re.match(r"python\s", "pythonXcpp").group() # 出错
re.match(r"python\S", "pythonXcpp").group()
re.match(r"python\S", "python\tcpp").group() # 出错
3.4 扩展
默认情况.是不能够匹配\n的 可以使用re.S模式让.匹配任意字符
re.match(r"python.org", "python\norg", re.S).group()
在python3中 \w还可以匹配汉字 因为是re.U Unicode模式
py2中默认使用 re.A ASCII \w只匹配数字字母 下划线
re.match(r"python\.org\w", "python.org我").group() # py3默认为UNICODE模式 可匹配汉字
re.match(r"python\.org\w", "python.org我", re.A).group() # 指定ASCII模式
4. 量词-匹配数量的字符
{m,n} 匹配至少m次 至多n次
{m} m次
{m,} 至少m次 无上限
re.match(r"嫦娥\d{1,10}号","嫦娥1号").group()
re.match(r"嫦娥\d{2,2}号","嫦娥10号").group()
re.match(r"嫦娥\d{2}号","嫦娥10号").group()
+ 匹配至少1次
re.match(r"嫦娥\d{1,}号","嫦娥10号").group()
re.match(r"嫦娥\d+号","嫦娥10号").group()
* 匹配任意次(0次)
re.match(r"嫦娥\d{0,}号","嫦娥号").group()
re.match(r"嫦娥\d*号","嫦娥1000号").group()
re.match(r"嫦娥\d*号","嫦娥号").group()
? 匹配0次或者1次
re.match(r"嫦娥\d{0,1}号","嫦娥号").group()
re.match(r"嫦娥\d?号","嫦娥号").group()
re.match(r"嫦娥\d?号","嫦娥1号").group()
思考:4到16个单词字符 @ qq.com
re.match(r"\w{4,16}@qq\.com","12345@qq.com").group()
5. 匹配位置
^ 匹配开始位置 区分: [^]取反
$ 匹配结束位置
r"^正则$"
re.match(r"\w{4,16}@qq\.com$","12345@qq.com").group()
re.match(r"^\w{4,16}@qq\.com$","12345@qq.com").group()
re.match(r"^[a-zA-Z_]\w*$", "1abc").group()
6. 分组group
6.1 匿名分组
目的: 从整体数据提取出 感兴趣的部分数据
创建: “(正则)”
用户创建的分组从1开始 0号分组已经存储整体结果
获取分组结果:
匹配结果对象.group(分组编号=0)
.group(编号,编号)
分组引用:
希望在正则的后续位置使用前面的分组匹配的数据
\分组的编号
re.match(r"嫦娥(\d+)号", "嫦娥998号").group()
re.match(r"嫦娥(\d+)号", "嫦娥998号").group(0)
re.match(r"嫦娥(\d+)号", "嫦娥998号").group(1)
re.match(r"嫦娥(\d+)号 998", "嫦娥998号 998").group(1)
re.match(r"嫦娥(\d+)号 999", "嫦娥999号 999").group(1)
# 上面写 不灵活 每次分组数据不一样全部需要改写
# 如果需要使用前面分组的数据继续匹配 - 分组引用
re.match(r"嫦娥(\d+)号 \1", "嫦娥999号 999").group(1)
re.match(r"嫦娥(\d+)号 \1", "嫦娥1999号 1999").group(1)
re.match(r"(\d{3,4})-\d{6,8}", "010-000001").group()
re.match(r"(\d{3,4})-\d{6,8}", "010-000001").group(1)
re.match(r"(\d{3,4})-(\d{6,8})", "010-000001").group(2)
re.match(r"(\d{3,4})-(\d{6,8}) \1-\2", "010-000001 010-000001").group(2)
6.2 命名分组
应用场景: 默认分组没有名称只能按照分组编号访问 而一旦分组编号发生变化导致正则修改
给每个分组起一个名称 编号发送变化不会影响正则的使用
创建
“(?P<分组名称>正则)”
获取结果
.group(分组名称)
* 也可以通过下标访问
创建分组并分组引用
“(?P<分组名称>正则) (?P=分组名称)”
re.match(r"(?P<area>\d{3,4})-(?P<no>\d{6,8}) (?P=area)-(?P=no)", "010-000001 010-000001").group(1,2)
re.match(r"(?P<area>\d{3,4})-(?P<no>\d{6,8}) (?P=area)-(?P=no)", "010-000001 010-000001").group('no')
re.match(r"((?P<area>\d{3,4})-(?P<no>\d{6,8})) (?P=area)-(?P=no)", "010-000001 010-000001").group('no')
6.3 分组其他使用
r"表达式1|表达式2|表达式3" 匹配|左右任意一个表达式
r"表达式(部分1|部分2|部分3)" 匹配分组中 |左右任意一个表达式
re.match(r"^\w{4,16}@163\.com$", "123456@163.com").group()
re.match(r"^\w{4,16}@163\.com$|^\w{4,16}@263\.com$|^\w{4,16}@qq\.com$", "123456@qq.com").group()
re.match(r"^\w{4,16}@(163|263|qq)\.com$", "123456@263.com").group()
7. 模块提供的方法
search(正则, 数据) -> 匹配结果对象 如果成功返回对象; 失败返回None
从头开始往后搜索 并且尝试匹配, 如果匹配失败会继续往后尝试 直到搜索完成
re.search(r"\d+", "python=100 cpp=96").group()
findall(正则, 数据) -> 匹配结果构成的列表
查找数据中所有满足正则规律的数据 返回列表
sub(参数1-正则,参数2-替换的数据,参数3=数据,参数4=次数) -> 数据被替换之后的结果
查找参数3 数据中 符合参数1规则的数据替换为参数2 参数4次数
次数默认为替换所有
如果参数2为"" 相当于删除了满足参数1规则的数据
了解 - 参数2可以是一个函数的引用
def 函数名(匹配结果对象):
根据匹配结果对象获取数据
对数据进行处理
返回处理之后的结果
re.sub(r"</?\w+>|\s| ", "", html)
split(正则, 数据) -> 切割之后的结果构成的列表
re.split(r":|,|\s", "貂蝉,杨玉环:西施,王昭君")
8 贪婪与懒惰模式
默认贪婪模式 尽可能多匹配-匹配结果很长
懒惰 尽可能少匹配
贪婪模式变为懒惰模式 **量词后加?**即可
前提: 满足整体的匹配结果
re.search(r"https://.+\.jpg", html_data).group() # 一个结果很长
re.search(r"https://.+?\.jpg", html_data).group() # 一个结果很短
# 理解贪婪模式和非贪婪模式之后 再看下面的代码
re.findall(r"https://.+?\.jpg|https://.+?\.png", html))
re.findall(r"https://.+?\.(?:jpg|png)", html))
# 取消分组 因为findall的结果默认是用户创建的分组数据 需要取消用户创建的分组从而显示整体结果(?:正则)
9. r字符的作用
如果字符串中有双斜杠 正则需要四反斜杠来进行匹配
为解决反斜杠困扰问题, 使用r标识数据
r"\1" ===> "\\1" 自动对数据中的\进行转义 ——> 双反斜杠 \\