python学习-正则
本文介绍 python 的正则表达式,包括
正则表达式
的基本语法、常用函数、匹配模式、分组捕获、贪婪匹配和非贪婪匹配、替换和分割字符串、编译正则表达式等。供自己以后查漏补缺,也欢迎同道朋友交流学习。
引言
上一篇文章介绍了程序的异常处理,但在处理异常的时候,我们经常要进行逻辑 if
判断,简单的就是比较相等或者大小,但真实场景里我们还需要判断是否是手机号
、银行卡号
、邮箱
、密码格式
...。
这时候就需要使用正则去更简单的进行逻辑判断和字符串匹配了。
因此,本章主要介绍 python
的正则表达式,包括正则表达式
的基本语法、常用函数、匹配模式、分组捕获、贪婪匹配和非贪婪匹配、替换和分割字符串、编译正则表达式等。
正则的用途
正则表达式(简称regex
或regexp
)是一种文本模式描述的方法,它由一系列字符组成,这些字符可以是普通字符(如字母 a
到 z
)、特殊字符(如.
*
?
)或两者的组合。
正则表达式用于描述
、匹配
、查找
和管理文本字符串
中的复杂模式。正则表达式的主要用途包括:
- 文本搜索:在大量文本中
查找特定
的单词或短语。 - 数据验证:
检查
电子邮件地址、电话号码、邮政编码等是否符合特定格式。 - 文本替换:在文本中
替换
或修改
特定的单词或短语。 - 数据提取:从复杂的文本数据中
提取
有用的信息。 - 文本分割:将文本
分割
成更小的部分,以便进一步处理。
基本语法
正则表达式的基本语法是构建正则表达式模式的基础,它包括字面量字符
、特殊字符
、元字符
、预定义字符类
和数量词
。
字面量字符
字面量字符
是指在正则表达式中直接表示其自身含义的字符。例如,字母a
、数字1
等都是字面量字符。
特殊字符和转义
特殊字符
在正则表达式中有特殊的含义,它们用于定义搜索模式的规则。为了匹配这些特殊字符本身,需要使用反斜杠 \
进行转义。
特殊字符 | 说明 |
---|---|
. | 匹配任意单个字符(除了换行符) |
^ | 匹配输入字符串的开始位置 |
$ | 匹配输入字符串的结束位置 |
* | 匹配前面的子表达式零次或多次 |
+ | 匹配前面的子表达式一次或多次 |
? | 匹配前面的子表达式零次或一次 |
[] | 匹配括号内的任意字符(字符集) |
| | 匹配两项之间的任意一项(或) |
\ | 转义特殊字符或表示特殊序列的开始 |
元字符
元字符
是正则表达式中具有特殊意义的字符,它们用于指定字符串的特定模式。包含了上面特殊字符,新增了一些特殊的含义。
元字符 | 说明 |
---|---|
... | ...上面的特殊字符 |
{n} | 表示前面的字符恰好出现 n 次 |
{n,} | 表示前面的字符至少出现 n 次 |
{n,m} | 表示前面的字符至少出现 n 次,但不超过 m 次 |
预定义字符类
预定义字符类
是正则表达式中用于匹配特定类型的字符集。
预定义字符类 | 说明 |
---|---|
\d | 匹配任意数字,等同于[0-9] |
\D | 匹配任意非数字字符,等同于[^0-9] |
\w | 匹配任意字母数字字符,包括下划线,等同于[a-zA-Z0-9_] |
\W | 匹配任意非字母数字字符,等同于[^a-zA-Z0-9_] |
\s | 匹配任意空白字符,包括空格、制表符、换行符等 |
\S | 匹配任意非空白字符 |
数量词
数量词
用于指定前面元素的出现次数
。
数量词 | 说明 |
---|---|
* | 匹配前面的子表达式零次或多次 |
+ | 匹配前面的子表达式一次或多次 |
? | 匹配前面的子表达式零次或一次 |
{n} | 表示前面的字符恰好出现 n 次 |
{n,} | 表示前面的字符至少出现 n 次 |
{n,m} | 表示前面的字符至少出现 n 次,但不超过 m 次 |
常用函数
re.match()
re.match()
函数尝试从字符串的开始位置
匹配正则表达式,如果字符串开始处就匹配
,则返回一个匹配对象
;否则返回 None
。
# 语法
# match_result = re.match(pattern, string, flags=0)
# pattern:正则表达式的模式字符串。
# string:要匹配的字符串。
# flags:编译时用的匹配模式,如re.IGNORECASE或re.MULTILINE。
import re
match_result = re.match(r'^\d+', '123abc')
if match_result:
print('@@@@ match 匹配成功', match_result.group())
else:
print("@@@@ match 匹配失败")
# 输出:@@@@ match 匹配成功 123
re.search()
re.search()
函数扫描整个字符串,寻找正则表达式的第一次
出现,如果找到匹配
,则返回一个匹配对象
;否则返回 None
。
# 语法
# search_result = re.search(pattern, string, flags=0)
# pattern:正则表达式的模式字符串。
# string:要匹配的字符串。
# flags:编译时用的匹配模式。
import re
search_result = re.search(r'^\d+', 'abc123def')
if search_result:
print('@@@@ search 匹配成功', search_result.group())
else:
print("@@@@ search 匹配失败")
# 输出:@@@@ search 匹配失败
re.findall()
re.findall()
函数找出字符串中所有匹配
正则表达式的子串,并返回一个列表。
# 语法
# all_matches = re.findall(pattern, string, flags=0)
# pattern:正则表达式的模式字符串。
# string:要匹配的字符串。
# flags:编译时用的匹配模式。
import re
all_matches = re.findall(r'\d+', 'abc123def456')
print("@@@@ findall 所有匹配", all_matches)
# 输出:@@@@ findall 所有匹配 ['123', '456']
re.finditer()
re.finditer()
函数返回一个迭代器,迭代器产生 Match
对象。这个函数类似于 re.findall()
,但它返回的是 Match
对象,而不是字符串列表,这使得可以访问匹配的详细信息。
# 语法
# finditer_result = re.finditer(pattern, string, flags=0)
# pattern:正则表达式的模式字符串。
# string:要匹配的字符串。
# flags:编译时用的匹配模式。
import re
for match in re.finditer(r'\d+', 'abc123def456'):
print("匹配:", match.group())
# 输出:
# 匹配: 123
# 匹配: 456
re.sub()
re.sub()
函数用于替换字符串中的正则表达式匹配项。它返回一个新的字符串
,其中所有的匹配都被替换。
# 语法
# new_string = re.sub(pattern, repl, string, count=0, flags=0)
# pattern:正则表达式的模式字符串。
# repl:替换匹配项的字符串或函数。
# string:要匹配的字符串。
# count:模式匹配后替换的最大次数,默认0表示替换所有匹配。
# flags:编译时用的匹配模式。
import re
new_string = re.sub(r'\d+', '数字', 'abc123def456', count=1)
print("@@@@ sub 替换结果", new_string)
# 输出:@@@@ sub 替换结果 abc数字def456
匹配模式
匹配模式
指的是用于识别字符串中特定模式的规则和结构。这些模式可以是简单的字符序列
,也可以是复杂的结构
,包括字符组合
、重复
、选择
等。
- 全匹配:要求整个字符串或字符串的特定部分
完全符合
正则表达式定义的模式。 - 部分匹配:只要求字符串中的
一部分符合
正则表达式定义的模式。
以下是一些匹配模式的例子和解释:
-
简单匹配
:- 模式:
\d+
- 描述:匹配
一个或多个
数字。 - 示例:在字符串"abc123def"中,\d+会匹配"123"。
- 模式:
-
字符类匹配
:- 模式:
[abc]+
- 描述:匹配
一个或多个
a、b或c。 - 示例:在字符串"xyzabc123"中,[abc]+会匹配"abc"。
- 模式:
-
范围匹配
:- 模式:
[a-z]
- 描述:匹配
任意一个
小写字母。 - 示例:在字符串"Hello World"中,[a-z]会匹配"ello"。
- 模式:
-
选择匹配
:- 模式:
(cat|dog)
- 描述:匹配"cat"或"dog"。
- 示例:在字符串"I have a cat"中,(cat|dog)会匹配"cat"。
- 模式:
-
重复匹配
:- 模式:
\d{3,5}
- 描述:匹配3到5个数字。
- 示例:在字符串"123456"中,\d{3,5}会匹配"123"、"1234"或"12345"。
- 模式:
-
位置匹配
:- 模式:
^admin
- 描述:匹配以"admin"开头的字符串。
- 示例:在字符串"admin123"中,^admin会匹配整个字符串。
- 模式:
-
结束匹配
:- 模式:
end$
- 描述:匹配以"end"结尾的字符串。
- 示例:在字符串"theend"中,end$会匹配"end"。
- 模式:
分组捕获
分组捕获
是一种将正则表达式的某部分括起来的机制,使得匹配到的字符串可以被单独提取出来。
分组使用圆括号()
来定义,它们不仅帮助我们匹配复杂的模式,还可以让我们访问匹配的具体部分。
分组的语法
- 普通分组:使用
圆括号()
将正则表达式的某部分括起来,如(abc)
。 - 非捕获分组:使用
?:后跟圆括号
来创建一个非捕获分组
,如(?:abc)
。这种分组用于分组而不捕获匹配的文本。
提取信息
从匹配的字符串中提取特定的子字符串。
import re
phone = "123-456-7890"
match = re.match(r"(\d{3})-(\d{3})-(\d{4})", phone)
print("区号:", match.group(1)) # 区号: 123
print("交换机号码:", match.group(2)) # 交换机号码: 456
print("线路号码:", match.group(3)) # 线路号码: 7890
分组引用
在同一个正则表达式中,后续的分组可以通过前面的分组捕获的内容进行匹配。
import re
text = "abc abc"
match = re.search(r"(\w+) \1", text)
if match:
print("匹配:", match.group())
# 输出: 匹配: abc abc
使用非捕获分组
使用?:后跟圆括号
来创建一个非捕获分组,这种分组用于分组而不捕获匹配
的文本。
import re
phone = "123-456-7890"
match = re.match(r"(?:\d{3})-(\d{3})-(\d{4})", phone)
if match:
print("交换机号码:", match.group(1)) # 交换机号码: 456
print("线路号码:", match.group(2)) # 线路号码: 7890
贪婪匹配与非贪婪匹配
在正则表达式中,量词(如*、+、?和{}
)可以指定一个模式出现的次数。默认情况下,这些量词是贪婪的,意味着它们会尽可能多
地匹配字符。
- 贪婪匹配:匹配尽可能
多
的字符。 - 非贪婪匹配:匹配尽可能
少
的字符。
非贪婪量词
要将量词从贪婪模式转换为非贪婪模式,可以在量词后面添加?
。
import re
text = "我是中国人,我爱中国。"
# 贪婪匹配
greedy_match = re.search(r"中国.*", text)
if greedy_match:
print("贪婪匹配:", greedy_match.group())
# 输出: 贪婪匹配: 中国,我爱中国。
# 非贪婪匹配
non_greedy_match = re.search(r"中国.*?", text)
if non_greedy_match:
print("非贪婪匹配:", non_greedy_match.group())
# 输出: 非贪婪匹配: 中国
替换和分割字符串
替换 re.sub()
在常用函数里已经介绍过了,这里就不再赘述了。
re.split()
re.split()
函数用于根据匹配正则表达式的模式来分割
字符串。它返回一个列表,其中包含被分割的部分。
# 语法
# split_result = re.split(pattern, string, maxsplit=0, flags=0)
# pattern:正则表达式的模式字符串。
# string:要匹配的字符串。
# maxsplit:分割的最大次数,默认0表示无限制。
# flags:编译时用的匹配模式。
import re
text = "apple,banana,cherry"
fruits = re.split(r',', text)
print(fruits)
# 输出:['apple', 'banana', 'cherry']
替换和分割的高级技巧
- 使用函数作为替换参数:
re.sub()
允许传递一个函数作为repl
参数,该函数接受一个匹配对象,并返回用于替换的字符串。
import re
text = "今天是2023-11-21"
def replace_with_comma(match):
return match.group().replace('-', ',')
new_text = re.sub(r'(\d+)-(\d+)-(\d+)', replace_with_comma, text)
print(new_text)
# 输出:今天是2023,11,21
- 限制分割次数:
re.split()
的maxsplit
参数可以用来限制分割的次数,这在处理大型文件或需要特定分割位置时非常有用。
import re
text2 = "apple,banana,cherry,date,fig"
fruits = re.split(r',', text2, maxsplit=2)
print(fruits)
# 输出:['apple', 'banana', 'cherry,date,fig']
编译正则表达式
正则表达式可以通过 re
模块提供的函数直接使用,但频繁使用相同的正则表达式模式时,每次都进行编译会降低效率
。
为了解决这个问题,可以使用 re.compile()
函数将正则表达式编译成正则表达式对象(Pattern
对象),这样可以提高匹配效率,尤其是在需要多次使用同一模式的情况下。
re.compile()
函数用于编译正则表达式模式,生成一个正则表达式对象。
# 语法
# pattern = re.compile(pattern, flags=0)
# flags:编译时用的匹配模式。
import re
pattern = re.compile(r'\d+')
result = pattern.match('123abc')
if result:
print("匹配成功:", result.group())
# 输出:匹配成功: 123
编译后的正则表达式对象提供了以下方法:
- match():从字符串的
开始位置匹配
正则表达式。 - search():扫描整个字符串,
寻找
正则表达式的第一次
出现。 - findall():找出字符串中
所有匹配
正则表达式的子串。 - finditer():
返回一个迭代器
,迭代器产生Match
对象。 - sub():
替换
字符串中的正则表达式匹配项。 - split():根据匹配正则表达式的模式来
分割
字符串。
正则高级技巧
使用断言
- 前瞻断言((?=...)):确保某个模式
后面
跟着特定的字符串。 - 后顾断言((?<=...)):确保某个模式
前面
是特定的字符串。 - 负向前瞻断言((?!...)):确保某个模式
后面不跟
着特定的字符串。 - 负向后顾断言((?<!...)):确保某个模式
前面不是
特定的字符串。
import re
# 匹配一个单词,它后面跟着"ing"
text = "I am running and I am swimming."
matches = re.findall(r'\b\w+(?=ing)', text)
print(matches)
# 输出: ['runn', 'swimm']
使用字符集和排除
- 利用字符集
[...]
来匹配一系列可能的字符。 - 使用
^
在字符集开始处排除
某些字符。
import re
# 匹配除了数字之外的任意字符
text2 = "abc123def456"
matches2 = re.findall(r'[^\d]+', text2)
print(matches2)
# 输出: ['abc', 'def']
python学习专栏系列
- python学习-基础学习1
- python学习-基础学习2
- python学习-基础学习3
- python学习-面向对象编程1
- python学习-面向对象编程2
- python学习-文件读写
- python学习-程序异常处理
- python学习-正则
- python学习-处理word文档
- python学习-处理pdf文档
- python学习-处理excel文档
- python学习-处理csv文档
- python学习-使用matplotlib绘制图表
- python学习-处理JSON数据
- python学习-SQLite数据库
- python学习-多线程处理
- python学习-网络爬虫