Python中的正则表达式

📅 2026/7/14 6:14:44 👁️ 阅读次数 📝 编程学习
Python中的正则表达式

一:正则表达式使用

1.什么是正则表达式?

正则表达式其实就是一套固定的规则,这套规则限制着字符串或者说是在过滤字符串

比如:

  • 规则 \d{11}:匹配11位数字,用来验证手机号
  • 规则 \w+@\w+.\w+:匹配邮箱格式

核心用途:

  • 验证:判断字符串是否符合规则(比如手机号、邮箱、身份证号格式是否正确);
  • 查找:从文本中找出所有符合规则的字符串(比如从新闻中提取所有日期);
  • 提取:从匹配结果中提取关键信息(比如从邮箱中提取用户名);
  • 替换:替换文本中符合规则的内容(比如过滤文本中的特殊字符)。

使用正则表达式之前需要进行导包:import re

使用正则表达式的核心流程:定义规则->执行匹配->提取结果

import re #导入正则表达式模块 res = re.match(r"h\w+","hello world") if res: print(res.group()) else: print("匹配失败!")

re.match()只会根据字符的开头进行匹配,如果开头错误会直接失败,失败会返回None。

2.匹配单个字符的规则符号

符号 / 写法匹配规则补充说明
.匹配除换行符\n外的任意单个字符开启re.DOTALL标志后,可匹配包含换行符在内的所有字符
[abc]匹配方括号内列举的任意一个字符集合内为 “或” 逻辑;绝大多数元字符(如.*)在集合内会失去特殊含义,仅作为普通字符匹配
[a-z]匹配指定字符范围内的任意一个字符-连接起止字符,支持[0-9][A-Za-z]等组合;-放在集合首尾时仅作为普通横杠字符匹配
[^abc]匹配不在方括号内的任意一个字符^必须放在集合开头才表示取反;放在集合中间时仅作为普通字符匹配
\d匹配任意单个数字字符ASCII 模式等价于[0-9];Python 3 默认 Unicode 模式还会匹配全角数字等,开启re.ASCII后仅匹配半角数字
\D匹配任意单个非数字字符\d的取反形式,ASCII 模式等价于[^0-9]
\w匹配任意单个单词字符ASCII 模式等价于[A-Za-z0-9_];Unicode 模式下还会匹配中文等语言文字
\W匹配任意单个非单词字符\w的取反形式,ASCII 模式等价于[^A-Za-z0-9_]
\s匹配任意单个空白字符包含空格、制表符\t、换行符\n、回车符\r、换页符\f、垂直制表符\v
\S匹配任意单个非空白字符\s的取反形式
\转义符,将正则元字符转义为普通字面字符用于匹配符号本身,例如\.匹配字面点号、\[匹配左中括号、\\匹配反斜杠本身

3.匹多个字符的规则符号

符号 / 写法匹配规则补充说明
*匹配前面的字符 / 分组 0 次或多次,贪婪模式尽可能多地匹配目标内容;等价写法为{0,}
+匹配前面的字符 / 分组 1 次或多次,贪婪模式被匹配内容至少出现 1 次;等价写法为{1,}
?匹配前面的字符 / 分组 0 次或 1 次,贪婪模式用于标记可选内容;等价写法为{0,1}
{n}匹配前面的字符 / 分组恰好 n 次n 为非负整数,例如\d{4}可匹配连续 4 位数字
{n,}匹配前面的字符 / 分组至少 n 次,贪婪模式匹配次数无上限,优先匹配尽可能多的内容
{n,m}匹配前面的字符 / 分组 n 到 m 次,贪婪模式包含 n 次和 m 次边界,优先匹配更多次数
量词+?将贪婪量词转为非贪婪(惰性)模式,尽可能少匹配常见写法:*?+???{n,m}?;正则默认贪婪匹配,追加?后转为最少匹配
( )分组,将括号内的多字符视为一个整体,可配合量词实现重复匹配例如(ab)+可匹配ababab等;同时会捕获分组内的匹配结果

OK!那现在就可以施展他们两的组合技了!!!

\d* 匹配任意数量的数字字符,\d+ 匹配任意数量的数字字符。

# \d* 匹配任意数量的数字字符 res1 = re.match("\d*","123abc") print(res1.group()) # \d+ 匹配任意数量的数字字符 res2 = re.match("\d+","123abc") print(res2.group())

他两的区别就是d*的结果可以为0以上的结果,d+只能为1以上的结果

\d? 最多匹配一个数字字符

# \d? 最多匹配一个数字字符 res = re.match("\d?","123abc") print(res.group())

手机格式验证:

phone1 = "13212345678" phone2 = "1321234567" phone3 = "132abcdefgh" res1 = re.match("\d{11}",phone1) print(res1.group()) # 输出13212345678 res2 = re.match("\d{11}",phone2) print(res2.group()) # 报错:AttributeError res3 = re.match("\d{11}",phone3) print(res3.group()) # 报错:AttributeError

4.核心规则:匹配开头和结尾

用^和$限定字符串的开头和结尾,确保整个字符串完全符合规则(避免部分匹配)。其实核心的意思就是打假,^打假开头防止尾部符合开头不符合规则;$符号打假尾部防止开头符合尾部不符合。

邮箱格式验证:

# 邮箱规则:数字/字母/下划线开头,@后面是数字字母,.后面是2-4位字母 #这里的\.表示只匹配.;如果写.表示匹配除换行符以外的所有字符 pattern = r"^\w+@\w+\.\w{2,4}$" # 要验证的邮箱 email1 = "abc123@qq.com" # 结果:abc123@qq.com email2 = "abc@123.xyz" # 结果:abc@123.xyz email3 = "abc123.com" # 结果:格式错误 email4 = "abc123@qq.com.cn" # 结果:格式错误 for email in [email1,email2,email3,email4]: res = re.match(pattern,email) if res: print(res.group()) else: print("格式错误")

5.核心规则:匹配分组(进阶)

用()将部分规则分组,可实现“多选一”或“引用分组结果”,适合复杂匹配场景。

5.1多选一(|)

规则:(规则1|规则2|规则3),匹配任意一个符合的规则,只要符合其中一条就能输出,否则报错。

pattern = r"(red|blue|black)" string1 = "blue" string2 = "green" res1 = re.match(pattern,string1) res2 = re.match(pattern,string2) print(res1.group()) #输出:blue print(res2.group()) #不匹配,程序报错

5.2引用分组结果(\num)

用\num引用前面第num个分组匹配的内容(比如匹配成对的HTML标签),适合成双成对出现的字符。(张三)在前面出现过,后面就使用 \数字 来代替,这里注意数字取决于第几个分组,而分组使用()来表示分组。

#<html>login</html> pattern = r"<(\w+)>\w+</\1>" string1 = "<html>login</html>" string2 = "<html>login</body>" res1 = re.match(pattern,string1) res2 = re.match(pattern,string2) print(res1.group()) #输出:<html>login</html> print(res2.group()) #不匹配,程序报错

二:常用函数

回顾:re.match()

功能:从字符串开头开始匹配,开头不符合就返回None。

res1 = re.match("th","this is a good day") print(res1.group()) #输出:th res2 = re.match("th","a good day") print(res2.group()) #报错

2.1核心函数:re.search()——全局找第一个匹配

功能·:search()会遍历整个字符串,不管开头是否匹配,只要找到第一个符合规则的就返回结果,如果没有就返回None,相当于文档里面的查找功能。

res1 = re.search("good","this is a good day") print(res1.group()) #输出:good res2 = re.search("is","this is a good day") print(res2.group()) #输出:is(出现多次只会返回第一个) res3 = re.search("cc","this is a good day") print(res3) #输出:None

2.2核心函数:re.findall()——找所有匹配项(返回列表)

功能:findall()会遍历整个字符串,找到所有符合规则的非重叠子串,并将所有获取到的结果以列表的形式返回,如果没有找到就返回空列表。

res1 = re.findall(r"\d","abcd1234@#$") print(res1) #输出:['1', '2', '3', '4'] res2 = re.findall(r"\w{3}","good123ABC_xyz") print(res2) #输出:['goo', 'd12', '3AB', 'C_x'] res3 = re.findall(r"\d","abcd@#$") print(res3) #输出:[]

2.3核心函数:re.sub()——替换匹配项

功能:sub()会遍历字符串,将所有匹配到规则的子串替换成指定内容;可以指定替换次数,默认情况下替换所有匹配项。

res1 = re.sub("is","am","hello,everyone! this is a good day!") print(res1) #输出:hello,everyone! tham am a good day! res2 = re.sub("is","am","hello,everyone! this is a good day!",count=1) print(res2) #输出:hello,everyone! tham is a good day!(只替换第一个) res3 = re.sub(r"\d","*","今天是第23天,温度是36°,湿度是48%") print(res3) #输出:今天是第**天,温度是**°,湿度是**% res4 = re.sub(r"\W","","sajs%&^$sa") print(res4) #输出:sajssa(删除所有特殊符号)

三:贪婪匹配&非贪婪匹配

3.1什么是贪婪匹配/非贪婪匹配?

正则:

贪婪模式(默认):量词(如*、+、{m,n})会尽可能的匹配多的字符,一直到无法匹配为止。

非贪婪模式:在量词后加?,量词会尽可能匹配少的字符,满足规则即可。

3.2关键前提:只影响量词的匹配行为

受影响的量词:

不受影响的规则:.、\d、[a-z]等单个字符匹配规则。

3.3贪婪模式:

正则默认是贪婪模式,不用额外加任何符号,量词会自动匹配尽可能多的字符。这里可以理解为规则范围内取最大值作为标准。

res1 = re.match(r"\d*","1234abcd") print(res1.group()) #输出:1234 res2 = re.match(r"\d+","1234abcd") print(res2.group()) #输出:1234 res3 = re.match(r"\d{2,3}","1234abcd") print(res3.group()) #输出:123

3.4非贪婪模式:

量词后面加?,能少拿就少拿。这里可以理解为规则范围内取最小值作为标准。

res1 = re.match(r"\d*?","1234abcd") print(res1.group()) #输出:""(空字符串) res2 = re.match(r"\d+?","1234abcd") print(res2.group()) #输出:1 res3 = re.match(r"\d{2,3}?","1234abcd") print(res3.group()) #输出:12

重点实例:模糊匹配中的差异(注意?需要加在量词后面)

res_greedy = re.match(r"a.*b",string) res_non_greedy = re.match(r"a.*?b",string) print(res_greedy.group()) #输出:a123b123b print(res_non_greedy.group()) #输出:a123b

3.5什么时候适合使用非贪婪模式?

常见场景:

1.提取:“最近匹配”的内容(如上面的a.*?b,提取a到最近的b)

2.避免匹配范围“过度扩大”(如提取HTML标签时,避免把多个标签当成一个)

3.明确需要“最少匹配”的场景(如匹配2-5个数字,只需要前2个)

示例:提取HTML标签中的内容(非贪婪必用)

string = "<div>第一部分</div><div>第二部分</div>" res_greedy = re.match(r"<div>.*</div>",string) res_non_greedy = re.match(r"<div>.*?</div>",string) print(res_greedy.group()) #输出:<div>第一部分</div><div>第二部分</div> print(res_non_greedy.group()) #输出:<div>第一部分</div>