python学习-正则
本文介绍 python 的正则表达式,包括正则表达式的基本语法、常用函数、匹配模式、分组捕获、贪婪匹配和非贪婪匹配、替换和分割字符串、编译正则表达式等。
供自己以后查漏补缺,也欢迎同道朋友交流学习。
引言
上一篇文章介绍了程序的异常处理,但在处理异常的时候,我们经常要进行逻辑 if 判断,简单的就是比较相等或者大小,但真实场景里我们还需要判断是否是手机号、银行卡号、邮箱、密码格式...。
这时候就需要使用正则去更简单的进行逻辑判断和字符串匹配了。
因此,本章主要介绍 python 的正则表达式,包括正则表达式的基本语法、常用函数、匹配模式、分组捕获、贪婪匹配和非贪婪匹配、替换和分割字符串、编译正则表达式等。
正则的用途
正则表达式(简称regex或regexp)是一种文本模式描述的方法,它由一系列字符组成,这些字符可以是普通字符(如字母 a 到 z)、特殊字符(如.*?)或两者的组合。
正则表达式用于描述、匹配、查找和管理文本字符串中的复杂模式。正则表达式的主要用途包括:
- 数据验证:
检查电子邮件地址、电话号码、邮政编码等是否符合特定格式。 - 文本分割:将文本
分割成更小的部分,以便进一步处理。
基本语法
正则表达式的基本语法是构建正则表达式模式的基础,它包括字面量字符、特殊字符、元字符、预定义字符类和数量词。
字面量字符
字面量字符是指在正则表达式中直接表示其自身含义的字符。例如,字母a、数字1等都是字面量字符。
特殊字符和转义
特殊字符在正则表达式中有特殊的含义,它们用于定义搜索模式的规则。为了匹配这些特殊字符本身,需要使用反斜杠 \ 进行转义。
元字符
元字符是正则表达式中具有特殊意义的字符,它们用于指定字符串的特定模式。包含了上面特殊字符,新增了一些特殊的含义。
预定义字符类
预定义字符类是正则表达式中用于匹配特定类型的字符集。
| |
|---|
\d | |
\D | |
\w | 匹配任意字母数字字符,包括下划线,等同于[a-zA-Z0-9_] |
\W | 匹配任意非字母数字字符,等同于[^a-zA-Z0-9_] |
\s | |
\S | |
数量词
数量词用于指定前面元素的出现次数。
常用函数
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
formatchin 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
匹配模式
匹配模式指的是用于识别字符串中特定模式的规则和结构。这些模式可以是简单的字符序列,也可以是复杂的结构,包括字符组合、重复、选择等。
- 全匹配:要求整个字符串或字符串的特定部分
完全符合正则表达式定义的模式。 - 部分匹配:只要求字符串中的
一部分符合正则表达式定义的模式。
以下是一些匹配模式的例子和解释:
- 示例:在字符串"abc123def"中,\d+会匹配"123"。
- 示例:在字符串"xyzabc123"中,[abc]+会匹配"abc"。
- 示例:在字符串"Hello World"中,[a-z]会匹配"ello"。
- 示例:在字符串"I have a cat"中,(cat|dog)会匹配"cat"。
- 示例:在字符串"123456"中,\d{3,5}会匹配"123"、"1234"或"12345"。
- 示例:在字符串"admin123"中,^admin会匹配整个字符串。
- 示例:在字符串"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)
ifmatch:
print("匹配:", match.group())
# 输出: 匹配: abc abc
使用非捕获分组
使用?:后跟圆括号来创建一个非捕获分组,这种分组用于分组而不捕获匹配的文本。
import re
phone = "123-456-7890"
match = re.match(r"(?:\d{3})-(\d{3})-(\d{4})", phone)
ifmatch:
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"
defreplace_with_comma(match):
returnmatch.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 对象。 - 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-study