正则表达式(python版最全面,最易懂)

正则表达式

正则表达式英文称regular expression

定义:正则表达式是一种文本模式匹配的工具,用于字符串的搜索,匹配和替换。在excel,word以及其他的文本编辑器都可直接适配。

一、基本匹配规则

  • 字面值字符:例如字母、数字、空格等,可以直接匹配它们自身。

  • 特殊字符:例如点号 .、星号 *、加号 +、问号 ? 等,它们具有特殊的含义和功能。

  • 字符类:用方括号 [ ] 包围的字符集合,用于匹配方括号内的任意一个字符。

  • 元字符:例如 \d\w\s 等,用于匹配特定类型的字符,如数字、字母、空白字符等。

  • 量词:例如 {n}{n,}{n,m} 等,用于指定匹配的次数或范围。

  • 边界符号:例如 ^$\b\B 等,用于匹配字符串的开头、结尾或单词边界位置。

1.字符匹配

普通字符匹配:直接匹配文本中的字符,如abc表示直接匹配文本中包含为"abc"的字符

元字符匹配:元字符具有特殊的含义,例如 \d 匹配任意数字字符,\w 匹配任意字母数字字符,. 匹配任意字符(除了换行符)等。

常见的元字符如下:

元字符 含义 示例
. 匹配任意单个字符(换行符除外) a.c 匹配 "abc"、"a1c"
^ 匹配字符串开头 ^abc 匹配 "abc123"
$ 匹配字符串结尾 abc$ 匹配 "123abc"
* 匹配前一个字符 0 次或多次 a* 匹配 "", "a", "aaa"
+ 匹配前一个字符 1 次或多次 a+ 匹配 "a", "aaa"
? 匹配前一个字符 0 次或 1 次 a? 匹配 "", "a"
{n} 匹配前一个字符 n 次 a{3} 匹配 "aaa"
{n,m} 匹配前一个字符 n 到 m 次 a{2,4} 匹配 "aa", "aaa", "aaaa"
[] 匹配字符集合中的任意一个字符 [abc] 匹配 "a", "b", "c" [a-z] 匹配小写字母 a 到 z 的任意一个 [0-9] 匹配数字 0 到 9 的任意一个 [^...]匹配不在括号内的任意字符(字符集的否定)
` ` 或运算
\ 转义字符,转义元字符或定义特殊字符 \d\s\w, C:\\Users\\Qiu
\d 匹配任何数字,相当于 [0-9]
\D 匹配任何非数字字符,相当于 [^0-9]
\w 匹配任何单词字符(字母、数字、下划线),相当于 [a-zA-Z0-9_]
\W 匹配任何非单词字符,相当于 [^a-zA-Z0-9_]
\s 匹配任何空白字符(空格、制表符、换行符等)
\S 匹配任何非空白字符
() 用于分组和捕获子表达式。 (\d{4})-(\d{2}-\d{2})\d{4}\d{2}-\d{2}分为两组,可以对这两组进行捕获以及后期直接引用 (\w{3})(\1) 表示匹配连续两段的字母,如abbabb
(?: ) 用于分组但不捕获子表达式。

2.量词匹配

  • *:匹配前面的模式零次或多次。

  • +:匹配前面的模式一次或多次。

  • ?:匹配前面的模式零次或一次。

  • {n}:匹配前面的模式恰好 n 次。

  • {n,}:匹配前面的模式至少 n 次。

  • {n,m}:匹配前面的模式至少 n 次且不超过 m 次。

3.字符类

  • [ ]:匹配括号内的任意一个字符。例如,[abc] 匹配字符 "a"、"b" 或 "c"。

  • [^ ]:匹配除了括号内的字符以外的任意一个字符。例如,[^abc] 匹配除了字符 "a"、"b" 或 "c" 以外的任意字符。

4.边界匹配(定位符)

定位符用来描述字符串或单词的边界,^$ 分别指字符串的开始与结束,\b 描述单词的前或后边界,\B 表示非单词边界。

  • ^:匹配字符串的开头。

  • $:匹配字符串的结尾。

  • \b:匹配单词边界。

  • \B:匹配非单词边界。

5.分组和捕获

  • ( ):用于分组和捕获子表达式。

  • (?: ):用于分组但不捕获子表达式。

6.特殊字符

  • \:转义字符,用于匹配特殊字符本身。

  • .:匹配任意字符(除了换行符)。

  • |:用于指定多个模式的选择。

7.分组与引用

() 表示分组,匹配子表达式并捕获;() 会把每个分组里的匹配的值保存起来, 多个匹配值可以通过数字 n 来查看(n 是一个数字,表示第 n 个捕获组的内容)。如:(\w{3})(\1) 表示匹配连续两段的字母,如abbabb

  • (\d{4})-(\d{2}-\d{2})\d{4}\d{2}-\d{2}分为两组,可以对这两组进行捕获以及后期直接引用

但用圆括号会有一个副作用,使相关的匹配会被缓存,此时可用 ?: 放在第一个选项前来消除这种副作用。即?: 仅于分组但不捕获子表达式。

其中?:为非捕获元之一,非捕获元表示不会将表达式内容包含在结果当中。同等的非捕获元还有?=?!

8.正、负向零宽断言

?=正向零宽断言 (Positive Lookahead)

  • exp1(?=exp2) 查找在exp2前面的exp1,且exp2不会包含在结果当中

  • (?<=exp2)exp1 表示查找在exp2前面的exp1,且exp2不会包含在结果当中

python 复制代码
import re
 ​
 pattern = r"I love (?=python)" # 匹配 "python" 前面带有 "I love " 的部分
 text = "I love python, I love coding."
 ​
 match = re.search(pattern, text)
 if match:
     print(match.group())  # 输出:I love

?!:负向零宽断言 (Negative Lookahead)

  • exp1(?!exp2) 查找在 exp2 后面不跟exp1,且 exp2 不会包含在结果当中。

  • (?<!exp2)exp1 查找在 exp2 前面不跟exp1,且 exp2 不会包含在结果当中。

python 复制代码
 import re
 ​
 pattern = r"I love (?!python)"
 text = "I love coding, I love python." # 匹配不以 "python" 结尾的 "I love "
 ​
 matches = re.findall(pattern, text)
 print(matches)  # 输出:['I love ']
复制代码
 

?=?!的区别:

特性 ?=(正向断言) ?!(负向断言)
断言结果 后面 必须是 pattern 后面 不能是 pattern
是否消耗字符
适用场景 验证后续内容符合预期 排除后续内容不符合预期

9.贪婪与非贪婪匹配

*+ 限定符都是贪婪的,因为它们会尽可能多的匹配文字,只有在它们的后面加上一个 ? 就可以实现非贪婪或最小匹配。

**贪婪匹配:**尽可能多地匹配。

  • 示例:a.*b 匹配 "a123b456b" 中的 "a123b456b"。

**非贪婪匹配:**尽可能少地匹配。

  • 语法:在元字符后加 ?

  • 示例:a.*?b 匹配 "a123b456b" 中的 "a123b"。

案例:如<.*>会匹配到如下html标签内的所有值

但是如果我们只需要匹配一个<h1>标签,我们可以使用非贪婪匹配:<.*?>

通过在 *+? 限定符之后放置 ?,该表达式从"贪婪"表达式转换为"非贪婪"表达式或者最小匹配。

10.标记/修饰符(flag)

符号 作用 示例
i ignore - 不区分大小写 将匹配设置为不区分大小写,搜索时不区分大小写: A 和 a 没有区别。
g global - 全局匹配 查找所有的匹配项。
m multi line - 多行匹配 使边界字符 ^$ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾。
s 特殊字符圆点 . 中包含换行符 \n 默认情况下的圆点 . 是匹配除换行符 \n 之外的任何字符,加上 s 修饰符之后, . 中包含换行符 \n。
  • i表示不区分大小写:
  • m表示多行匹配(每行都进行匹配)
  • 默认情况下的圆点 . 是 匹配除换行符 \n 之外的任何字符,加上 s 之后, . 中包含换行符 \n

python re库内的正则表达式支持的修饰符(可选标志)

re.IGNORECASE (re.I):忽略大小写。

re.MULTILINE (re.M):多行模式,^$ 会匹配每一行的开头和结尾。

re.DOTALL (re.S):单行模式,使 . 匹配换行符。

re.VERBOSE (re.X):允许在正则表达式中添加注释和多行书写。

其他标志如 re.ASCIIre.LOCALE 等。

二、Python正则表达式API使用

Python 提供了 re 模块用于操作正则表达式。

函数 含义
re.match 从字符串开头匹配,返回 Match 对象
re.search 在字符串中搜索第一个匹配
re.findall 返回所有匹配结果的列表
re.finditer 返回所有匹配结果的迭代器
re.sub 替换匹配到的内容
re.split 按正则表达式分割字符串

1.查找

方法 作用描述
re.match 从字符串的开头尝试匹配正则表达式,只返回第一个匹配的对象。
re.search 搜索整个字符串,返回第一个匹配的对象。
re.findall 搜索所有符合正则表达式的内容,返回匹配结果的列表。
re.finditer 搜索所有符合正则表达式的内容,返回一个迭代器(每项是 Match 对象)。

1.re.match/re.search

re.match 只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None,而 re.search 匹配整个字符串,直到找到一个匹配。

复制代码
 re.match(pattern, string, flags=0) # pattern正则表达式;string需要匹配的字符;flag修饰符模式。match匹配字符串的开始,如果字符串开始不符合正则表达式,则返回None,否则返回一个Match对象
 re.search(pattern, string, flags=0) # re.search 匹配整个字符串,匹配成功返回一个Match对象,否则返回None

Match对象方法:

  • group(num=0) 当查找字符串分组时,group(num) 将返回对应num组的元组(1开始分组),group(0)/group(num)表示全部匹配字符串。

  • groups() 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。

复制代码
 
python 复制代码
import re
 ​
 line = "Cats are smarter than dogs"
 ​
 # 匹配字符串的开始,如果开始不成功,则匹配失败
 matchObj = re.match(r"dogs", line, re.M | re.I)  # return:None
 if matchObj:
     print(matchObj.group())
 else:
     print("No match!!") # No match!!
 ​
 # 匹配整个字符串直到找到至少一个匹配
 matchObj = re.search(r"dogs", line, re.M | re.I)  # return:dogs
 if matchObj:
     print(matchObj.group()) # dogs
 else:
     print("No match!!")
     
 分组
 text2 = "18812345678,他还有一个电话号码是18887654321,他爱好的数字是01234567891,他的座机是:0571-52152166,0571-52152177"
 m1 = re.search(
     r"(\d{4})-(\d{8})", text2
 )  # 返回一个Match对象,调用Match对象的group方法获取返回值
 print(m1.group())  # 0571-52152166
 print(m1.group(1))  # 0571,取表达式的第一组匹配值(\d{4})
 print(m1.group(2))  # 52152166,取表达式的第二组匹配值(\d{8})

2.findall

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果有多个匹配模式,则返回元组列表,如果没有找到匹配的,则返回空列表。

复制代码
 re.findall(pattern, string, flags=0)
 或
 pattern.findall(string[, pos[, endpos]])
  • pattern 匹配模式。

  • string 待匹配的字符串。

  • pos 可选参数,指定字符串的起始位置,默认为 0。

  • endpos 可选参数,指定字符串的结束位置,默认为字符串的长度。

python 复制代码
import re
  
 result1 = re.findall(r'\d+','runoob 123 google 456')
  
 pattern = re.compile(r'\d+')   # 查找数字
 result2 = pattern.findall('runoob 123 google 456')
 result3 = pattern.findall('run88oob123google456', 0, 10)
  
 print(result1) # ['123', '456']
 print(result2) # ['123', '456']
 print(result3) # ['88', '12']
 ​
 多个匹配模式,返回元组列表
 import re
 ​
 result = re.findall(r'(\w+)=(\d+)', 'set width=20 and height=10')
 print(result) # [('width', '20'), ('height', '10')]

3.re.finditer

findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。

python 复制代码
re.finditer(pattern, string, flags=0)
 import re
  
 it = re.finditer(r"\d+","12a32bc43jf3") 
 for match in it: 
     print(match.group())
 12 
 32 
 43 
 3

findallfinditer的区别

  • findall返回的可能是元组列表,也可能是字符串列表,取决于正则表达式内是否分组

  • finditer返回的是Match对象的迭代器

2.替换

替换功能可以用正则表达式匹配到的部分内容进行替换,主要通过 re.subre.subn 方法实现。

方法 作用描述
re.sub 替换匹配到的内容,返回替换后的新字符串。
re.subn 替换匹配到的内容,返回元组 (新字符串, 替换次数)
  • sub:返回替换后的字符串。

  • subn:返回包含替换后字符串和替换次数的元组。

1.re.sub&re.subn

复制代码
 re.sub(pattern, repl, string, count=0, flags=0) # 前三个为必选参数,后两个为可选参数。
  • pattern : 正则中的模式字符串。

  • repl : 替换的字符串,也可为一个函数。

  • string : 要被查找替换的原始字符串。

  • count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。

  • flags : 编译时用的匹配模式,数字形式。

复制代码
 
python 复制代码
import re
  
 phone = "2004-959-559 # 这是一个电话号码"
  
 # 删除注释
 num = re.sub(r'#.*$', "", phone)
 print ("电话号码 : ", num)
  
 # 移除非数字的内容
 num = re.sub(r'\D', "", phone)
 print ("电话号码 : ", num)
 # 当repl 参数是一个函数
 import re
  
 # 将匹配的数字乘以 2
 def double(matched):
     value = int(matched.group('value'))
     return str(value * 2)
  
 s = 'A23G4HFD567'
 print(re.sub('(?P<value>\d+)', double, s)) # A46G8HFD1134

subn和sub用法一样,只是subn会额外将替换的次数一起封装成元组返回

python 复制代码
text = "abc,adfasda,Abc,ABC"
 sub = re.sub(r"(abc)", "***", text, flags=re.I)
 subn = re.subn(r"(abc)", "***", text, flags=re.I)
 print(sub)  # re.sub返回替换后的字符串,***,adfasda,***,***
 print(subn)  # re.subn返回替换后的字符串和替换次数的元组,('***,adfasda,***,***', 3)

3.分割split

复制代码
 re.split(pattern, string[, maxsplit=0, flags=0])
  • pattern 正则表达式

  • string 需要匹配的字符串

  • maxsplit 分割次数,maxsplit=1 分割一次,默认为 0表示不限制次数。

  • flags 标志位

python 复制代码
 text6 = "abc,  ddd? xxx. fff! asd"
 split = re.split(
     r"\s*[,?!.]\s*", text6
 )  # 将【,?!.】符号以及旁边的空格作为分隔符分割字符串,返回一个字符串数组
 print(split)  # ['abc', 'ddd', 'xxx', 'fff', 'asd']
 ​
 re.split('a*', 'hello world')   # 对于一个找不到匹配的字符串而言,split 不会对其作出分割
 # ['hello world']

4.compile

compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。语法格式为:

复制代码
 re.compile(pattern[, flags])
  • pattern : 一个字符串形式的正则表达式

  • flags 可选,表示匹配模式,比如忽略大小写,多行模式等

  • 返回 RegexObject 对象,该对象可以调用匹配方法(如 matchsearchfindall 等)。

python 复制代码
 # 编译正则表达式
 pattern = re.compile(r"\d+")
 ​
 # compile
 # 使用编译的正则对象进行匹配和查找
 result1 = pattern.findall("There are 3 cats and 4 dogs.")
 result2 = pattern.findall("There are 6 cats and 8 dogs.")
 print(result1)  # 输出 ['3', '4']
 print(result2)  # 输出 ['6', '8']

re.compile() 是处理复杂正则表达式的最佳选择,尤其是需要频繁使用相同的正则时。它能提高代码效率、增强可读性,是 Python 正则表达式模块中非常重要的功能。

相关推荐
萧鼎2 分钟前
使用Python的Tabulate库优雅地格式化表格数据
python
程序员小远8 分钟前
接口自动化测试框架(pytest+allure+aiohttp+ 用例自动生成)
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·pytest
钮钴禄·爱因斯晨34 分钟前
赛博算命之 ”梅花易数“ 的 “JAVA“ 实现 ——从玄学到科学的探索
java·开发语言·python
卜及中1 小时前
【Go语言快速上手】第二部分:Go语言进阶
开发语言·后端·golang
进阶的小叮当2 小时前
Vue+Node调用Python并将结果显示到Web页面中
vue.js·python·node.js
BuHuaX2 小时前
C#元组和Unity Vector3
开发语言·unity·c#·游戏引擎·全文检索
《雨声》2 小时前
第3章《VTK可视化基础》
开发语言·c++·qt·算法
Perfect_www2 小时前
Jupyter Notebook自动保存失败等问题的解决
ide·python·jupyter
好想写博客2 小时前
[深度学习]神经网络-回归项目
pytorch·python·深度学习·神经网络·回归·numpy·pandas
一晌小贪欢2 小时前
Python办公笔记——将csv文件转Json
笔记·python·json·python办公·python读取csv