Python正则表达式

正则表达式用于查找符合规则的字符串。正则表达式具备通用性,所以是用处最广泛的字符串匹配语法,无论是Python、Java、PHP,还是数据库语言SQL,它的语法规则是基本通用的。

Python使用正则表达式主要分为三步

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1.导入正则表达式的模块
import re

# 2.使用方法进行匹配操作,例如match
result = re.match('正则表达式', '要匹配的字符串')

# 3.拿到匹配的结果数据,可以通过group方法获取
print(result.group())

# example
result = re.match('正则', '正则表达式字符串')
print(result.group)

匹配单个字符

代码 功能
. 匹配任意1个字符 (除了\n)
[] 匹配[]中列举的字符
\d 匹配数字,即0-9
\D 匹配非数字即不是数字
\s 匹配空白即空格,tab键
\S 匹配非空白
\w 匹配非特殊字符,即a-zA-Z、0-9、_、汉字
\W 匹配特殊字符,即非字母、非数字、非_汉字
1
2
3
4
5
6
7
8
import re
ret = re.match(".","A")
print(ret.group())
ret = re.match("zho..hou","zhouzhou")
print(ret.group())
ret = re.match("zho..hou","zhoZUhou")
print(ret.group())
# 没有特别的标识,正则里是严格区分字母的大小写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 如果hello的首字符小写,那么正则表达式需要小写的h
ret = re.match("h","hello Python")
print(ret.group())
# 如果hello的首字符大写,那么正则表达式需要大写的H
ret = re.match("H","Hello Python")
print(ret.group())
# 大小写h都可以的情况
ret = re.match("[hH]","hello Python")
print(ret.group())
ret = re.match("[hH]","Hello Python")
print(ret.group())
ret = re.match("[hH]ello Python","Hello Python")
print(ret.group())
# 这里的中括号表示,只要是括号里面的字符都可以满足匹配条件
# 例如匹配数字
ret = re.match("[0123456789]zhou zhou","6zhou zhou")
print(ret.group())
ret = re.match("[0‐9]zhou zhou","2zhou zhou")
print(ret.group())
# 下面括号里的写法表示匹配的数据是0到3和5到9
ret = re.match("[0‐35‐9]zhou zhou","5zhou zhou")
print(ret.group())
# 所以,当我们想要匹配4的时候就会没有结果
ret = re.match("[0‐35‐9]zhou zhou","4zhou zhou")
print(ret.group())
1
2
3
4
5
6
7
# \d 匹配数字
ret = re.match('第\d号', '第8号当铺')
print(ret.group())
# \D 指定不匹配数字
ret = re.match('第\D号', '第八号当铺')
print(ret.group())
# 除了上面匹配数字的方法,还能通\d进行匹配

匹配空白字符 \s

1
2
3
4
5
6
7
8
9
10
 ret = re.match("周周\szhouzhou", "周周 zhouzhou")
print(ret.group())
# 这里的\t属于空白字符
ret = re.match("周周\szhouzhou", '周周\tzhouzhou')
print(ret.group())
# \S 匹配非空白字符
ret = re.match("周周\Szhouzhou", "周周*zhouzhou")
print(ret.group())
ret = re.match("周周\Szhouzhou", '周周Wzhouzhou')
print(ret.group())

匹配多个字符

代码 功能
* 匹配前一个字符出现0次或者无限次,即可有可无
+ 匹配前一个字符出现1次或者无限次,即至少有1次
? 匹配前一个字符出现1次或者0次,即要么有1次,要么没有
{m} 匹配前一个字符出现m次
{m,n} 匹配前一个字符出现从m到n次
这里的符号机制是只作用前面一个字符的匹配。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import re
# [A‐Z][a‐z]* 表示大写字母匹配一次,小写字母随意匹配次数
ret = re.match("[A‐Z][a‐z]*","MdueD6Ddas")
print(ret.group())
ret = re.match("[A‐Z][a‐z]*","AdwtrMnnM")
print(ret.group())
ret = re.match("[A‐Z][a‐z]*","4Aabcdef")
print(ret.group())
ret = re.match("[A‐Z][a‐z]*","db4Aabcdef")
print(ret.group())
# [A‐Z][a‐z]+ 表示大写字母匹配一次,小写字母至少匹配一次
ret = re.match("[A‐Z][a‐z]+","MdueD6Ddas")
print(ret.group())
ret = re.match("[A‐Z][a‐z]+","AdwtrMnnM")
print(ret.group())
ret = re.match("[A‐Z][a‐z]+","a4Aabcdef")
print(ret.group())
ret = re.match("[A‐Z][a‐z]*","Pb4Aabcdef")
print(ret.group())

这里的星号和加号(* +)只表示匹配的次数

1
2
ret = re.match("https?", "http")
print(ret.group())
{m}、{m,n}
1
2
3
4
5
6
7
8
9
ret = re.match("\d{8}","1384775830245678")
print(ret.group())
# 从第一个满足条件的字符开始,匹配6到10次
ret = re.match("\d{6,10}","1384775830245678")
print(ret.group())
ret = re.match("\d{6,10}","13d4775830245678")
print(ret.group())
ret = re.match("\d{6,10}","1384775a30245678")
print(ret.group())

比较上面3次的结果可以知道,当满足了最低限制的6次匹配后,只要有不满足匹配条件的字符出现,匹配即结束。
如果没有满足最低的匹配次数,则表示匹配失败。

匹配开头结尾

代码 功能
^ 匹配字符串开头
$ 匹配字符串结尾
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import re
# 匹配数字开头的数据
result = re.match("^\d.*", "3tisugou")
if result:
print(result.group())
else:
print("匹配失败")
# 匹配数字结尾的数据
result = re.match(".*\d$", "tisugou2")
if result:
print(result.group())
else:
print("匹配失败")
# 匹配数字开头和数字结尾的数据
result = re.match("^\d.*\d$", "9tisugou2")
if result:
print(result.group())
else:
print("匹配失败")

除了指定字符以外都匹配

1
2
3
4
5
6
7
8
9
10
11
# 匹配一个除了zhou的字符
result = re.match("[^zhou]", "h")
if result:
print(result.group())
else:
print("匹配失败")
result = re.match("[^zhou]", "a")
if result:
print(result.group())
else:
print("匹配失败")

匹配分组

分组数是从左到右的方式进行分配的,所以数据也是从左到右来匹配的。

1
2
3
4
5
6
7
8
9
# 匹配列表中的元素
lyst = ['a', 'b', 'e', 'd', 'p']
for i in lyst:
# 匹配左右任意一个表达式
result = re.match(".+|[a-z]|\S", i)
if result:
print(result.group(), '匹配成功')
else:
print(i, '匹配失败')

正则表达式匹配应用

邮箱地址的匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 优化邮箱地址的匹配
# 1、邮箱的名称可以是任何字母、数字加下划线组成 ‐‐ [a‐zA‐Z0‐9_]
# 2、前面的匹配次数不少于4次,不多余30次 ‐‐ {4,30}
# 3、有@隔开
# 4、可以是网易、126、腾讯、新浪、雅虎的地址 ‐‐ (163|126|qq|sina|yahoo)
# 5、点(.)因为是特殊字符,所以需要用斜杠转译 ‐‐ \.
# 6、结尾可以是com 或者cn ‐‐ (com|cn)
pattern = "[a-zA-Z0-9_]{4,30}@(163|126|qq|sina|yahoo)\.(com|cn)"
result = re.match(pattern, "hadafdac@163.com")
if result:
print(result.group())
else:
print("匹配失败")

匹配手机号码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 手机号码有11位
# 一定是1开头
# 2、3位可能是30、37、38、39、40、41、47、56、80(具体有多少记不清了)
# 剩下的8位全是数字
pattern = '^1(30|37|38|39|40|41|47|56|80)\d{8}$'
result = re.match(pattern, "13094112846")
if result:
print(result.group())
else:
print("匹配失败")
# 也可以在查清楚不同电话的运营商后,优化规则
pattern = '^1(3[0‐9]|5[0‐3,5‐9]|7[1‐3,5‐8]|8[0‐9])\d{8}$'
result = re.match(pattern, "13094112846")
if result:
print(result.group())
else:
print("匹配失败")

匹配网址

1
2
3
4
5
6
7
8
9
# 常规网站的网址是www.开头的,论坛不考虑
# 结尾部分是.com 或者.cn
# 中间可以有任何字母或者数字,但是中间的部分是一定要有的
pattern = "^(www)\.[a-zA-Z0-9]+\.(com|cn)$"
result = re.match(pattern, "www.aiqiyi.com")
if result:
print(result.group())
else:
print("匹配失败")

命名匹配

有时候查看网页源码时,经常看到这样结构的字符串

www.baidu.com

这里来写正则的时候,前后的

如果写两次会觉得十分重复,而且还不易区分。 所以我们可以用到将匹配好的字符进行命名,方便后面的重复使用。
1
2
3
4
5
6
7
pattern = "<(P<name1>[a-zA-Z1-6]+)><(?P<name2>[a-zA-Z1-6]+)>.*</(?P=name2)></(?P=name1)?"
match_obj = re.match(pattern,"<html><h1>www.baidu.com</h1></html>")

if match_obj:
print(match_obj.group())
else:
print("匹配失败")

re模块的其他匹配用法

根据正则表达式查找一次数据,即为找到了第一个,就不会去找第二个了。

1
2
3
4
5
6
match_obj = re.search("\d+", "周周已经30岁了,提速狗才10岁")
if match_obj:
# 获取匹配结果数据
print(match_obj.group())
else:
print("匹配失败")

findall

找到所有满足条件的数据 ,并且以列表返回。

1
2
3
4
5
6
match_obj = re.findall("\d+", "周周已经30岁了,提速狗才10岁")
if match_obj:
# 获取匹配结果数据
print(match_obj)
else:
print("匹配失败")

虽然匹配的是数字,但是结果中的元素是字符串。

sub

将匹配到的数据进行替换。

1
2
3
4
5
match_obj = re.sub("\d+", '18', "周周已经30岁了,提速狗才10岁" ,count=1)
if match_obj:
print(match_obj)
else:
print("匹配失败")

sub的4个参数:
pattern:正则表达式,这里是 ‘\d+’
repl:替换后的字符串,这里是 ‘18’
string:需要匹配的字符串,这里是 ‘周周已经30岁了,提速狗才10岁’
count:替换次数,默认全部替换 ,即为count=0是全部替换

split

匹配并进行切割字符串,并返回一个列表。

1
2
3
4
5
6
7
8
9
pattern = ',|,|、|。'
string = '香蕉、苹果、菠萝,栗子。猕猴桃'
result = re.split(pattern, string)
print(result)
# 也可以限定分割次数,比如分割一次
pattern = ',|,|、|。'
string = '香蕉、苹果、菠萝,栗子。猕猴桃'
result = re.split(pattern, string, maxsplit=1)
print(result)

贪婪和非贪婪匹配

贪婪匹配是匹配尽可能多的字符,非贪婪则是相反,只要有满足条件的字符完成匹配,就立马结束。而Python里数
量词默认是贪婪的。

1
2
3
4
5
6
7
8
9
10
# 贪婪
s="A phone number 130‐9411‐2846"
r=re.match(".+(\d+‐\d+‐\d+)",s)
print(r.group(0))
print(r.group(1))
# 非贪婪
s="A phone number 130‐9411‐2846"
r=re.match(".+?(\d+‐\d+‐\d+)",s)
print(r.group(0))
print(r.group(1))

这里可以看到,r.group(1)在前后两次的匹配中结果不同
正则表达式模式中使用到通配字,那它在从左到右的顺序求值时,会尽量“抓取”满足匹配最长字符串,在
我们上面的例子里面,“.+”会从字符串的启始处抓取满足模式的最长字符,其中包括我们想得到的第一个整型字段的
中的大部分,“\d+”只需一位字符就可以匹配,所以它匹配了数字“0”,而“.+”则匹配了从字符串起始到这个第一位数
字0之前的所有字符。
解决方式:非贪婪操作符 ? ,这个操作符可以用在”*”,”+”,”?”的后面,这样?前面的正则表达式不能匹配?后
面正则表达式的数据

r原生字符串

之前的正则中,需要用反斜杠 \ 对一些特殊字符进行转译,但是如果我们就是需要去匹配反斜杠呢?此时可以用到r
写在正则的匹配规则之前,做到将正则的规则字符串看作原生的字符,即为不需要再去转译的字符

1
2
3
4
5
6
7
8
m = "d:\\a\\b\\c"
print(m)
ret = re.match("d:\\\\", m).group()
print(ret) # 'd:\\' ‐ 'd:\'
ret = re.match("d:\\\\a", m).group()
print(ret)
ret = re.match(r"d:\\a", m).group()
print(ret)

Python正则表达式
https://43.242.201.154/2024/09/08/python0/
Author
Dong
Posted on
September 8, 2024
Licensed under