规则
\d 匹配任意数字
\D 匹配任意非数字
\s 匹配任意空白字符
\S 匹配任意非空白字符
\w 匹配任意字母、数字或下划线
\W 匹配任意非字母、数字或下划线
. 匹配任意字符
^ 匹配字符串的开头
$ 匹配字符串的末尾
[] 匹配括号内的任意字符
[^] 匹配不在括号内的任意字符
* 匹配前面的字符0次或多次
+ 匹配前面的字符1次或多次
? 匹配前面的字符0次或1次
{n} 匹配前面的字符恰好n次
{n,} 匹配前面的字符至少n次
{n,m} 匹配前面的字符至少n次,至多m次
| 匹配两个或多个表达式中的任意一个
(...) 匹配括号内的表达式,并记住匹配的文本
(?...) 匹配括号内的表达式,但是不记住匹配的文本
(?P<name>...) 匹配括号内的表达式,并记住匹配的文本,并把匹配的文本保存到一个名字为name的组中
(?P=name) 匹配之前的命名组name匹配的文本
(?#...) 注释,不参与匹配
(?=...) 正向肯定界定符,在...前面的字符必须匹配
(?!...) 正向否定界定符,在...前面的字符不能匹配
(?<=...) 反向肯定界定符,在...后面的字符必须匹配
(?<!...) 反向否定界定符,在...后面的字符不能匹配
(?imxs) 正则表达式选项,i表示忽略大小写,m表示多行匹配,s表示使.匹配所有字符,x表示忽略空格和#后面的注释
(?-imxs) 正则表达式选项,-表示关闭选项
1. 字符匹配
正则表达式在网络爬虫、数据分析中有着广泛使用,掌握正则表达式能够达到事半功倍的效果。
1.1 方法和功能
方法 | 功能 |
---|---|
match() | 判断一个正则表达式是否从开始处匹配一个字符串 |
search() | 遍历字符串,找到正则表达式匹配的第一个位置,返回匹配对象 |
findall() | 遍历字符串,找到正则表达式匹配的所有位置,并以列表的形式返回。如果给出的正则表达式中包含子组,就会把子组的内容单独返回,如果有多个子组就会以元组的形式返回。 |
finditer() | 遍历字符串,找到正则表达式匹配的所有位置,并以迭代器的形式返回 |
hqyj匹配文本中的hqyj
import re
text="hqyj牛皮6666,hqyj有个老师也牛皮666"
data=re.findall("hqyj",text)
print(data)#['hqyj', 'hqyj']
[hqyj]匹配h或者q或者y或者j字符
import re
text="hqyj牛皮6666,hqyj有个老师也牛皮666"
data=re.findall("[hqyj]",text)
print(data)#['h', 'q', 'y', 'j', 'h', 'q', 'y', 'j']
import re
text="hqyj牛皮6666,hqyj有个老师也牛皮666"
data=re.findall("[hqyj]牛",text)
print(data)#['j牛']
[^hqyj]匹配除了hqyj以外的其他字符
import re
text="hqyj牛皮6666,hqyj有个老师也牛皮666"
data=re.findall("[^hqyj]",text)
print(data)#['牛', '皮', '6', '6', '6', '6', ',', '有', '个', '老', '师', '也', '牛', '皮', '6', '6', '6']
[a-z]匹配a~z的任意字符([0-9]也可以)
import re
text = "hqyj牛皮6666,hqyj有个老师abchqyj也牛皮666"
data = re.findall("[a-z]hqyj", text)
print(data) # ['chqyj']
.匹配除了换行符以外的任意字符
import re
text="hqyj牛皮6666,hqyj有个老师abchqyj也牛皮666"
data=re.findall(".hqyj",text)
print(data)#[',hqyj', 'chqyj']
import re
text="hqyj牛皮6666,hqyj有个老师abchqyj也牛皮666"
data=re.findall(".+hqyj",text) #贪婪匹配(匹配最长的)
print(data)#['hqyj牛皮6666,hqyj有个老师abchqyj']
import re
text="hqyj牛皮6666,hqyj有个老师abchqyj也牛皮666"
data=re.findall(".?hqyj",text)
print(data)#['hqyj', ',hqyj', 'chqyj']
1.2 特殊字符
特殊字符 | 含义 |
---|---|
\d | 匹配任何十进制数字;相当于类 [0-9] |
\D | 与 \d 相反,匹配任何非十进制数字的字符;相当于类 0-9 |
\s | 匹配任何空白字符(包含空格、换行符、制表符等);相当于类 [ \t\n\r\f\v] |
\S | 与 \s 相反,匹配任何非空白字符;相当于类 \t\n\r\f\v |
\w | 匹配任意一个文字字符,包括大小写字母、数字、下划线,等价于表达式[a-zA-Z0-9_] |
\W | 于 \w 相反 (注:re.ASCII 标志使得 \w 只能匹配 ASCII 字符) |
\b | 匹配单词的开始或结束 |
\B | 与 \b 相反 |
\w 匹配字母数字下划线(汉字)
import re
text = "华清_远见abc 华清hqyj远见 华清牛皮远见"
data = re.findall(r"华清\w+远见", text)
print(data) # ['华清_远见', '华清hqyj远见', '华清牛皮远见']
\d匹配数字
import re
text = "hqyj66d6 a1h43d3fd43s43d4 "
data = re.findall(r"d\d", text) # 只匹配一个数字
print(data) # ['d6', 'd3', 'd4', 'd4']
import re
text = "hqyj66d6 a1h43d3fd43s43d4 "
data = re.findall(r"d\d+", text)
print(data) # ['d6', 'd3', 'd43', 'd4']
\s匹配任意空白符 包括空格,制表符等等
import re
text = "hqyj666 jack karen 666"
data = re.findall(r"\sj\w+\s", text)
print(data) # [' jack ']
#[] 匹配括号内的任意字符
#[a-z],[1-9],[A-Z] 匹配指定范围内的任意字符
#[^a-z] 匹配不在指定范围内的任意字符
#[a-zA-Z0-9] 匹配任意字母、数字或下划线
x = re.findall("[abc]", "abcagdfasafaadfaafa") #查找所有小写字母
print(x) #['a', 'a', 'a'] #['a', 'b', 'c', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a']
#[^] 匹配不在括号内的任意字符
#[^a-zA-Z0-9] 匹配任意非字母、数字或下划线
x = re.findall("[^abc]", "abcagdfasafaadfaafa") #查找所有非小写字母
print(x) #['g', 'd', 'f', 's', 'f', 'd', 'f', 'f']
# . 匹配任意字符,点代表任意字符,
x = re.findall(".a", "abcagdfasafaadfaafa") #查找所有以a结尾的字符
print(x) #['ca', 'fa', 'sa', 'fa', 'fa', 'fa']
# \d 匹配任意数字
x = re.findall("\d","fds55fsdaf66saf77")
print(x) #['5', '5', '6', '6', '7', '7']
# \D 匹配任意非数字
x = re.findall("\D","fds55fs")
print(x) #['f', 'd', 's', 'f', 's']
x = re.findall("\Ds","fds55fs")
print(x) #['ds', 'fs']
# \s 匹配任意空白字符
x = re.findall("\s","fds 55fs daf6 6saf77")
print(x) #[' ', ' ', ' ']
x = re.findall("\sd","fds d55fs daf6 6saf77")
print(x) #[' d', ' d']
#\b 匹配单词边界,指的是一个单词的开始或结束,也就是单词的开头或结尾,单词边界的位置是不固定的,可以出现在单词中间,但是不能出现在单词的中间
x = re.findall("\b","fds 55fs daf6 6saf77")
print(x)
#+ 匹配前面的字符1次或多次
x =re.findall("[1-9]+","15616afdaf454585ssdgf")
print(x)
#以.jpg结尾
x = re.findall(r"^电话\d+","电话15gfdg电话465")
print(x) #电话15
#以.jpg结尾
x = re.findall(r"\d\.jpg$","电话15gfdg.jpg 电话465.jpg")
print(x)
2. 数量控制
控制匹配规则的重复次数~
2.1 *重复0次或多次
import re
text="华清远见 华清666远见"
data=re.findall("华清6*远见",text)
print(data)#['华清远见', '华清666远见']
2.2 +重复1次或多次
import re
text="华清远见 华清666远见 华清6远见"
data=re.findall("华清6+远见",text)
print(data)#['华清666远见', '华清6远见']
2.3 ?重复1次或0次
import re
text="华清远见 华清666远见 华清6远见"
data=re.findall("华清6?远见",text)
print(data)#['华清远见', '华清6远见']
2.4 {n}重复n次
import re
text="华清远见 华清666远见 华清6远见"
data=re.findall("华清6{3}远见",text)
print(data)#['华清666远见']
2.5 {n,}重复n次或多次
import re
text="华清远见 华清666远见 华清6远见 华清66远见"
data=re.findall("华清6{2,}远见",text)
print(data)#['华清666远见', '华清66远见']
2.6 {n,m}重复n到m次
import re
text="华清远见 华清666远见 华清6远见 华清66远见"
data=re.findall("华清6{0,2}远见",text)
print(data)#['华清远见', '华清6远见', '华清66远见']
3. 分组
()提取兴趣区域
import re
text = "谢帝谢帝,我要迪士尼,我的电话号码18282832341,qq号码1817696843"
data = re.findall(r"号码(\d{10,})", text)
print(data) # ['18282832341', '1817696843']
import re
text = "谢帝谢帝,我要迪士尼,我的电话号码18282832341,qq号码1817696843"
data = re.findall(r"(\w{2}号码(\d{10,}))", text)
print(data) # ['18282832341', '1817696843']
(|)提取兴趣区域(| = or)
import re
text = "第一名张三 第一名物理149分 第一名数学150分 第一名英语148分 第一名总分740分"
data = re.findall(r"第一名(\w{2,}|\w{2,}\d{2,}分)", text)
print(data) # ['张三', '物理149分', '数学150分', '英语148分', '总分740分']
4. 开始和结束
^开始
import re
text = "hqyj66abc hqyj123"
data = re.findall(r"^hqyj\d+", text)
print(data) # ['hqyj66']
$结尾
import re
text = "hqyj66abc hqyj123"
data = re.findall(r"hqyj\d+$", text)
print(data) # ['hqyj123']
5. 特殊字符
由于正则表达式中* . \ {} () 等等符号具有特殊含义,如果你指定的字符正好就是这些符号,需要用\进行转义
import re
text = "数学中集合的写法是{2}"
data = re.findall(r"\{2\}", text)
print(data) # ['{2}']
6. 常用方法
6.1 re.findall
获取匹配到的所有数据
import re
text="hqyj66d6 a1h43d3fd43s43d4 "
data=re.findall("d\d+",text)
print(data)#['d6', 'd3', 'd43', 'd4']
6.2 re.match
从字符串的起始位置匹配,成功返回一个对象否则返回none。
匹配成功返回对象,对象的方法:
方法 | 功能 |
---|---|
group() | 返回匹配的字符串 |
start() | 返回匹配的开始位置 |
end() | 返回匹配的结束位置 |
span() | 返回一个元组表示匹配位置(开始,结束) |
import re
# 在起始位置匹配,并返回一个包含匹配 (开始,结束) 的位置的元组
print(re.match('www', "www.python.com").span()) # (0, 3)
print(re.match('www', "www.python.com").start()) # 0
print(re.match('www', "www.python.com").end()) # 3
# 不在起始位置匹配
print(re.match('com', "www.python.com")) # None
6.3 re.search
扫描整个字符串并返回第一个成功匹配的字符串。成功返回一个对象否则返回none
import re
# 在起始位置匹配
print(re.search('www', 'www.hqyj.com').span()) # (0, 3)
# 不在起始位置匹配
print(re.search('com', 'www.hqyj.com').span()) # (9, 12)
6.4 re.sub
替换匹配成功的字符
类似与字符串的replace函数
import re
text = "以前华清远见在四川大学旁边,现在华清远见在西南交大旁边"
data = re.sub("华清远见", "北京华清远见科技集团成都中心", text)
print(data) # 以前北京华清远见科技集团成都中心在四川大学旁边,现在北京华清远见科技集团成都中心在西南交大旁边
6.5 re.split
根据匹配成功的位置对字符串进行分割
import re
text = "python is very easy"
data = re.split(r"\s{1,}", text)
print(data) # ['python', 'is', 'very', 'easy']
6.6 re.finditer
类似findall 但是不会全部返回出来 而是返回迭代器(比如匹配成功了10万个 全部返回就很吃内存了)
import re
text = "python is very easy"
data = re.findall(r"\w+", text)
print(data) # ['python', 'is', 'very', 'easy']
import re
text = "python is very easy"
data = re.finditer(r"\w+", text)
print(data)
for el in data:
print(el.group())
7. 常见正则
QQ号:[1 - 9][0 - 9]{4, }(腾讯QQ号从10000开始)
帐号(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
身份证号(15位、18位数字):^\d{15}|\d{18}$
短身份证号码(数字、字母x结尾):^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$