第一课、初始正则表达式
一、课程介绍
1.1 课程概要
步骤介绍
正则表达式入门及应用
正则的进阶
案例
综合项目实战
二、正则表达式的基本操作(多敲代码多做练习)
2.1 什么是正则表达式
什么是正则表达式
正则表达式(简称为regex)是一些有字符和特殊符号组成的字符串
能按照某种模式匹配一系列有相似特征的字符串 例如:[a-z]表示26个小写英文字母
正则表达式中的符号
符号 | 描述 | 示例 |
literal | 匹配文本字符串的字面值literal | foo |
re1|re2 | 匹配正则表达式re1或者re2 | foo|bar |
. | 匹配任何字符(除了\n之外) | b.b |
^ | 匹配字符串起始部分 | ^Dear |
$ | 匹配字符串终止部分 | /bin/*sh$ |
* | 匹配0次或者多次前面出现的正则表达式 | [A-Za-z0-9]* |
+ | 匹配1次或者多次前面出现的正则表达式 | [a-z]+\.com |
? | 匹配0次或者1次前面出现的正则表达式 | goo? |
{N} | 匹配N次前面出现的正则表达式 | [0-9]{3} |
{M,N} | 匹配M~N次前面出现的正则表达式 | [0-9]{5,9} |
[...] | 匹配来自字符集的任意单一字符 | [aeiou] |
[..x-y..] | 匹配x~y范围中的任意单一字符 | [0-9][A-Za-z] |
[^...] | 不匹配此字符集中出现的任何一个字符,包括某一范围的字符(如果在此字符集中出现) | [^aeiou],[^A-Za-z0-9] |
(*|+|?|{})? | 用于匹配上面频繁出现/重复出现符号的非贪婪版本(*、+、?、{}) | *?[a-z] |
(...) | 匹配封闭的正则表达式,然后另存为子组 | ([0-9]{3})?,f(oo|u)bar |
正则表达式中的特殊字符
特殊字符 | 描述 | 示例 |
\d | 匹配任何十进制数字,与[0-9]一致(\D与\d相反,不匹配任何非数值型的数字) | data\d+.txt |
\w | 匹配任何字母数字字符,与[A-Za-z0-9]相同(\W与之相反) | [A-Za-z_]\w+ |
\s | 匹配任何空格字符,与[\n\t\r\v\f]相同(\S与之相反) | of\sthe |
\b | 匹配任何单词边界(\B与之相反) | \bThe\b |
\N | 匹配已保存的子组N(参见上面的(...)) | price:\16 |
\c | 逐字匹配任何特殊字符c(即,仅按照字面意义匹配,不匹配特殊含义) | \.,\\,\* |
\A(\Z) | 匹配字符串的起始(结束)(另见上面介绍的^和$) | \ADear |
正则表达式中的扩展表示法
扩展表示法 | 描述 | 示例 |
(?iLmsux) | 在正则表达式中嵌入一个或者多个特殊"标记"参数(或者通过函数/方法) | (?x),(?im) |
(?:…) | 表示一个匹配不用保存的分组 | (?:\w+\.)* |
(?P<name>…) | 像一个仅由name标识而不是数字ID标识的正则分组匹配 | (?P<data>) |
(?P=name) | 在同一字符串中匹配由(?P<name)分组的之前文本 | (?P=data) |
(?#…) | 表示注释,所有内容都被忽略 | (?#comment) |
(?=…) | 匹配条件是如果…出现在之后的位置,而不使用输入字符串;称作正向前视断言 | (?=.com) |
(?!…) | 匹配条件是如果…不出现在之后的位置,而不使用输入字符串;称作负向前视断言 | (?!.net) |
(?<=…) | 匹配条件是如果…出现在之前的位置,而不使用输入字符串;称作正向后视断言 | (?<=800-) |
(?<!…) | 匹配条件是如果…不出现在之前的位置,而不使用输入字符串;称作负向后视断言 | (?<!192\.168\.) |
(?(id/name)Y|N) | 如果分组所提供的id或name(名称)存在,就返回正则表达式的条件匹配Y,如果不存在,就返回N;|N是可选项 | (?(1)y|x) |
使用正则表达式
简单匹配:例如:abc=>abc
多个匹配模式:例如:abc|12c=>abc,12c
匹配任意字符(.),除\n之外:例如:.=>abc.12c
2.2 正则表达式的使用
使用正则表达式
*匹配0次或者多次
+匹配一次或者多次
?匹配0次或者一次
{N}匹配指定的N次
{M,N}匹配M-N次,最大化优先
2.3 正则表达式匹配同类型及边界匹配
匹配同类型
\d匹配数字
\w匹配数字和字母
\s匹配任何空格字符
边界匹配
用^匹配以**开头
用$匹配以**结尾
2.4 正则表达式匹配选项
匹配特殊字符
需要用“\”进行转义
使用[]指定要匹配的集合
使用[^]指定不要匹配的内容
2.5 正则表达式分组
正则表达式分组
重复一个字符串时
使用()进行分组,使用(?<word>\w+)指定组名
从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推
使用()对匹配的内容分组
使用\1、\2反向引用
2.6 贪婪模式vs非贪婪模式
贪婪模式vs非贪婪模式
贪婪匹配
在整个表达式匹配成功的前提下,尽可能多的匹配
非贪婪匹配
在整个表达式匹配成功的前提下,以最少的匹配字符
默认是贪婪模式
贪婪模式举例
表达式ab.+c
测试数据:abacaxcd
匹配结果:abacaxc
非贪婪模式
只需要在匹配pattern中加上“?”
表达式ab.*?c
测试数据:abacaxcd
匹配结果:abac
三、 实战:正则表达式的应用
实战:身份证号码的正则匹配
正则表达式联系
身份证号码匹配正则表达式编写
电子邮箱正则表达式
四、 正则表达式进阶
4.1 正则的进阶介绍
课程概要
re模块
findall()的使用
search()的使用
group()与groups()的使用
split()正则分割
Sub()正则替换
课程目标
掌握compile()和match()函数的使用
掌握findall()和search()函数的使用
math()和search()的区别
掌握group()、groups()、groupdict()的基本使用
掌握split()、sub()的基本使用
教学思路
先理论
后代码实战
跟着来
4.2 re模块介绍
re模块
属性 | 描述 |
re.I、re.IGNORECASE | 不区分大小写的匹配 |
re.L、re.LOCALE | 根据所使用的本地语言环境通过\w、\W、\b、\B、\s、\S实现匹配 |
re.M、re.MULTILINE | ^和$分别匹配目标字符串中行的起始和结尾,而不是严格匹配整个字符串本身的起始和结尾 |
re.S、re.DOTALL | “.”(点号)通常匹配除了\n(换行符)之外的所有单个字符;该标记表示“.”(点号)能够匹配全部字符 |
re.X、re.VERBOSE | 通过反斜杠转义,否则所有空格加上#(以及在该行中所有后续文字)都被忽略,除非在一个字符类中或者允许注释并且提高可读性 |
re模块-compile
compile(pattern,flag = 0)
使用任何可选的标记来编译正则表达式的模式,然后返回一个正则表达式对象
推荐编译,但它不是必须的
re模块-match
match(pattern,string,flag = 0)
尝试使用带有可选的标记的正则表达式的模式来匹配字符串。如果匹配成功,就返回匹配对象;如果失败,就返回None
1 import re
2
3 # 将正则表达式编译
4 pattern = re.compile(r'hello', re.I)
5 print(dir(pattern))
6
7 # 通过match进行匹配
8 rest = pattern.match('Hello,world')
9 print(rest)
10 print(dir(rest))
11 print('string', rest.string)
12 print('re:', rest.re)
13 print(rest.groups())
4.3 findall和search
findall()的使用
findall(pattern,string[,flags])
查找字符串中所有(非重复)出现的正则表达式模式,并返回一个匹配列表
1 import re
2
3 # 找出一下字符串中的数字
4
5 content = 'One1Two22three333four4444five55555six666666'
6
7 # 使用编译的对象
8 p = re.compile(r'[a-z]+', re.I)
9 rest = p.findall(content)
10 print(rest)
11
12 # 不编译
13 all_rest = re.findall(r'[a-z]+', content, re.I)
14 print(all_rest)
search()的使用
search(pattern,string, flags = 0)
使用可选标记搜索字符串中第一次出现的正则表达式模式。如果匹配成功,则返回匹配对象;如果失败,则返回None
1 import re
2
3 # 找出一下字符串中的数字
4
5 content = 'hello, world'
6
7 # 使用编译的对象
8 p = re.compile(r'world')
9 # 使用search
10 rest = p.search(content)
11 print(rest)
12
13 # 使用match
14 rest_match = p.match(content)
15 print(rest_match)
16
17 # 使用函数进行调研
18 rest_func = re.search(r'world', content)
19 print(rest_func)
4.4 正则表达式的分组(group()与groups())
group()与groups()的使用
group(num)返回整个匹配对象或编号为num的特定子组
groups():返回一个包含所有匹配子组的元组(如果没有成功匹配,则返回一个空组)
1 import re
2
3 def test_group():
4 content = 'hello, world'
5 p=re.compile(r'world')
6 rest = p.search(content)
7 print(rest)
8 if rest:
9 # group的使用
10 print(rest.group())
11 # groups的使用
12 print(rest.groups())
13
14
15
16 def test_id_card():
17 """身份证号码正则匹配"""
18 # p = re.compile(r'(\d{6})(\d{4})((\d{2})(\d{2}))(\d{2}\d{1})([0-9]|X)')
19 p = re.compile(r'(\d{6})(?P<year>\d{4})((?P<mouth>\d{2})(?P<day>\d{2}))(\d{2}\d{1})([0-9]|X)')
20 # 准备两个身份证号
21 id ='230381199310070329'
22 rest1 = p.search(id)
23 print(rest1.group(2))
24 print(rest1.groups())
25 print(rest1.groupdict())
26
27 if __name__ == '__main__':
28 #test_group()
29 test_id_card()
4.5 正则表达式的分割和替换
split()正则分割
split(pattern, string, max=0)
根据正则表达式的模式分隔符,split函数将字符串分割为列表,然后返回成功匹配的列表,分割最多操作max次(默认分割所有匹配成功的位置)
1 import re
2
3 """
4 使用split正则分割字符串
5 """
6
7 s = 'one1two2three3four4five5six6'
8 p = re.compile(r'\d+')
9 rest = p.split(s, 2)
10 print(rest)
sub()正则替换
sub(pattern,repl,string,max=0)
使用repl替换string中每一个匹配的子串后返回替换后的字符串,最多操作max次(默认替换所有)
1 import re
2
3 """
4 使用正则表达式进行替换
5 """
6 s = 'one1two2three3four4five5six6'
7 # one@two@three@four@five@six@
8
9 #使用正则替换
10 p = re.compile(r'\d+')
11 rest = p.sub('@', s)
12 print(rest)
13
14 # 使用字符串原始替换方式
15 rest_origin = s.replace('1', '@').replace('2', '@').replace('3', '@').replace('4', '@').replace('5', '@').replace('6', '@')
16 print(rest_origin)
17
18 s2 = 'hello world'
19 # 使用正则表达式
20 p2 = re.compile(r'(\w+) (\w+)')
21 rest_pos = p2.sub(r'\2 \1', s2)
22 print(rest_pos)
23
24
25 # 在原有的内容基础上,替换并改变内容
26 def f(m):
27 """使用函数进行替换规则改变"""
28 return m.group(2).upper() + ' ' + m.group(1)
29
30
31 rest_change = p2.sub(f, s2)
32 print(rest_change)
33
34
35 # 使用匿名函数进行替换 lambda
36 rest_lamb = p2.sub(lambda m: m.group(2).upper() + ' ' + m.group(1), s2)
37 print('--------')
38 print(rest_lamb)
五、 正则综合实战(多练多看)
5.1 实战:正则匹配图片地址的需求分析
# 1. 下载html
# 2. 写正则的规则
# 要找到img标签
# 找到src属性
# <img class="" style="" src="xxx" xx="">
# <img.+src=\".+\".+>
5.2 实战:代码实现正则匹配图片地址
1 import re
2
3 def test_re_img():
4 """ 使用正则表达式找到图片的地址 """
5 # 1.读取html
6 with open('img.html', encoding='utf-8') as f:
7 html = f.read()
8 # print(html)
9 # 2. 准备正则
10 p = re.compile(r'<img.+?src=\"(?P<src>.+?)\".+?>', re.I)
11 # 使用findall找到图片的列表
12 list_img = p.findall(html)
13 print(len(list_img))
14 for ls in list_img:
15 print(ls.replace('&', '&'))
16 #TODO 使用urllib,requests将图片保存
17
18
19
20 if __name__ == '__main__':
21 test_re_img()
六、 课程总结
课程总结
什么是正则表达式
正则表达式匹配N次
匹配同类型及边界匹配
正则表达式匹配选项
正则表达式分组
贪婪模式VS非贪婪模式
正则表达式分析练习
知识点回顾
什么是正则表达式
正则表达式(简称为regex)是一些由字符和特殊符号组成的字符串
能按照某种模式匹配一系列有相似特征的字符串
例如:[a-z]表示26个小写字母
使用正则表达式
简单匹配:例如:abc => abc
多个匹配模式:例如:abc|12c =>abc,12c
匹配任意字符(.),除\n之外:例如:. => abc, 12c
*匹配0次或者多次
+匹配一次或者多次
?匹配0次或者1次
{N}匹配指定的N次
{M-N}匹配M-N次,最大化优先
匹配同类型
\d匹配数字
\w匹配数字和字母
\s匹配任何空格字符
边界匹配
用^匹配以**开头
用$匹配以**结尾
匹配特殊字符
需要用“\”进行转义
指定匹配选项
使用[]指定要匹配的集合
使用[^]指定不要匹配的内容
正则表达式分组
重复一个字符串时
使用()进行分组,使用(?<word>\w+)指定组名
从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推
使用()对匹配的内容分组
使用\1、\2反向引用
贪婪模式VS非贪婪模式
贪婪模式
在整个表达式匹配成功的前提下,尽可能多的匹配
非贪婪模式
在整个表达式匹配成功的前提下,以最少的匹配字符
只需在匹配pattern中加上“?”
表达式ab.*?c
测试数据:abacaxcd
匹配数据:abac
默认是贪婪模式
正则表达式练习
身份证号码匹配正则表达式编写
电子邮箱正则表达式编写
手机号码正则表达式编写
重点知识
理解什么是正则表达式以及它的用途
正则表达式的基本语法
正则表达式的编写和验证
正则表达式的分组及反向引用
难点知识
正则表达式的贪婪与非贪婪模式
正则表达式的分析方法