到此为止,所介绍的 Python 正则表达式内容足可以开发实际项目了。
但是为了提高效率, 还可以对 Python 正则表达式进行编译。
编译的正则表达式可以重复使用,这样能减少正则表达式的解析和验证,提高效率。
在 re
模块中的 compile()
函数可以编译正则表达式,compile()
函数语法如下:
re.compile(pattern[, flags=0])
其中:
- 参数 pattern 是正则表达式
- 参数 flags 是编译标志
compile()
函数返回一个编译的正则表达式对象 regex
。
13.6.1 已编译正则表达式对象
compile()
函数返回一个编译的正则表达式对象,该对象也提供了文本的匹配、查找和替换等操作的方法。
如下表所示是己编译正则表达式对象方法与 re 模块函数对照表:
常用函数 | 已编译正则表达式对象方法 | Re模块函数 |
---|---|---|
search() | regex.search(string[, pos[,endpos]]) | re.search(pattern,string,flags = 0) |
match() | regex.match(string[, pos[,endpos]]) | re. match (pattern,string,flags = 0) |
findall() | regex.findall(string[, pos[,endpos]]) | re. findall (pattern,string,flags = 0) |
finditer() | regex.finditer(string[,pos[,endpos]]) | re. finditer(pattern,string,flags = 0) |
sub() | regex.sub(string[, pos[,endpos]]) | re.sub(pattern,repl,string,count,flags=0) |
split() | regex.split(string[, pos[,endpos]]) | re.split(pattern,string,maxsplit=0,flags=0) |
正则表达式方法需要一个己编译的正则表达式对象才能调用,这些方法与 re
模块函数功能类似,这里不再一一赘述。
注意方法 search()
、match()
、findall()
和 finditer()
中的参数 pos
为开始查找的索引,参数 endpos
为结束查找的索引。
示例代码如下:
import re
p = r"\w+@zhijieketang\.com"
regex = re.compile(p)
text = "Tony's email is tony_guan588@zhijieketang.com."
m = regex.search(text)
print(m)
m = regex.match(text)
print(m)
p = r"[Jj]ava"
regex = re.compile(p)
text = "I like Java and java."
match_list = regex.findall(text)
print(match_list)
match_iter = regex.finditer(text)
for m in match_iter:
print(m.group())
p = r"\d+"
regex = re.compile(p)
text = "AB12CD34EF"
clist = regex.split(text)
print(clist)
repace_text = regex.sub(" ", text)
print(repace_text)
执行结果:
<re.Match object; span=(16, 45), match='tony_guan588@zhijieketang.com'>
None
['Java', 'java']
Java
java
['AB', 'CD', 'EF']
AB CD EF
上述代码都是编译正则表达式,然后通过己编译的正则表达式对象 regex 调用方法实现文本匹配、查找和替换等操作。这些方法与 re 模块函数类似。
13.6.2 编译标志
compile() 函数编译正则表达式对象时,还可以设置编译标志。
编译标志可以改变正则表达式引擎行为。
13.6.2.1 ASCII 和 Unicode
本节详细介绍几个常用的编译标志:
1:ASCII 和 Unicode
预定义字符 \w
和 \W
,其中 \w
匹配单词字符,在 Python 2 中是 ASCII 编码,在 Python3 中则是 Unicode 编码,所以包含任何语言的单词字符。
可以通过编译标志 re.ASCII(或 re.A)设置采用 ASCII 编码,通过编译标志 re.UNICODE(或 re.U)设置采用 Unicode 编码。
示例代码如下:
import re
text = "你们好 Hello"
p = r"\w+"
# 设置编译标志为 Unicode 编码
regex = re.compile(p, re.U)
# search() 方法匹配 “你们好Hello” 字符串
m = regex.search(text)
print(m)
# match() 方法也可匹配 “你们好Hello” 字符串
m = regex.match(text)
print(m)
# 设置编译标志为 ASCII 编码
regex = re.compile(p, re.A)
# 用 search() 方法匹配 “Hello” 字符串
m = regex.search(text)
print(m)
# match() 方法不可匹配
m = regex.match(text)
print(m)
执行结果:
<re.Match object; span=(0, 3), match='你们好'>
<re.Match object; span=(0, 3), match='你们好'>
<re.Match object; span=(4, 9), match='Hello'>
None
13.6.2.2 忽略大小写
默认情况下正则表达式引擎对大小写是敏感的,但有时在匹配过程中需要忽略大小写 ,可以通过编译标志 re.IGNORECASE
(或re.I
)实现。
示例代码如下:
import re
# 定义正则表达式
p = r"(java).*(python)"
# 编译正则表达式,设置编译参数 re.I 忽略大小写
regex = re.compile(p, re.I)
m = regex.search("I like Java and Python.")
print(m)
m = regex.search("I like JAVA and Python.")
print(m)
m = regex.search("I like java and Python.")
print(m)
执行结果:
<re.Match object; span=(7, 22), match='Java and Python'>
<re.Match object; span=(7, 22), match='JAVA and Python'>
<re.Match object; span=(7, 22), match='java and Python'>
由于忽略了大小写,代码中三个 search() 方法都能找到匹配的字符串。
13.6.2.3 点元字符匹配换行符
默认情况下正则表达式引擎中点 “.
” 元字符可以匹配除换行符外的任何字符,但是有时需要点 “.
” 元字符也能匹配换行符,这可以通过编译标志re.DOTALL
(或 re.S
)实现。
示例代码如下:
import re
p = r".+"
# 编译正则表达式时没有设置编译标志
regex = re.compile(p)
# 配结果是 "Hello" 字符串
# 因为正则表达式引擎遇到换行符 "\n" 时
# 认为它是不匹配的,就停止查找
m = regex.search("Hello\nWorld.")
print(m)
# 编译了正则表达式,并设置编译标志 re.DOTALL
regex = re.compile(p, re.DOTALL)
# 匹配结果是 "Hello\nWorld" 字符串
# 因为正则表达式引擎遇到换行符 "\n" 时
# 认为它是匹配的,会继续查找
m = regex.search("Hello\nWorld.")
print(m)
执行结果:
<re.Match object; span=(0, 5), match='Hello'>
<re.Match object; span=(0, 12), match='Hello\nWorld.'>
13.6.2.4 多行模式
编译标志 re.MULTILINE
(或 re.M
)可以设置为多行模式,多行模式对于元字符 ^
和 $
行为会产生影响。
默认情况下 ^
和 $
匹配字符串的开始和结束,而在多行模式下 ^
和 $
匹配任意一行的开始和结束。
示例代码如下:
import re
# 定义了正则表达式 ^World
# 匹配 World 开头的字符串
p = r"^World"
# 进行编译时并没有设置多行模式
regex = re.compile(p)
# 代码 "Hello\nWorld" 字符串是不匹配的
# 虽然 "Hello\nWorld" 字符串事实上是两行
# 但默认情况 ^World 只匹配字符串的开始
m = regex.search("Hello\nWorld.")
print(m)
# 重新编译了正则表达式
# 此时设置了编译标志 re.M 开启多行模式
# 在多行模式下 ^ 和 $ 匹配字符串任意一行的开始和结束
regex = re.compile(p, re.M)
# 匹配 World 字符串
m = regex.search("Hello\nWorld.")
print(m)
执行结果:
None
<re.Match object; span=(6, 11), match='World'>
13.6.2.5 详细模式
编译标志 re.VERBOSE
(或 re.X
)可以设置详细模式。
详细模式 下可以在正则表达式中添加注释,可以有空格和换行,这样编写的正则表达式非常便于阅读。
示例代码如下:
import re
# 定义的正则表达式原本是 (java).*(python)
# 现在写成多行表示,其中还有注释和空格等内容
# 如果没有设置详细模式,这样的正则表达式会抛出异常
# 由于正则表达式中包含了换行等符号
# 所以需要使用双重单引号或三重双引号括起来
# 而不是使用原始字符串
p = """(java)
.*
(python)
"""
# 编译正则表达式时,设置了两个编译标志 re.I 和 re.VERBOSE
# 当需要设置多编译标志时,编译标志之间需要位或运算符 "|"
regex = re.compile(p, re.I|re.VERBOSE)
m = regex.search("I like Java and Python.")
print(m)
m = regex.search("I like JAVA and Python.")
print(m)
m = regex.search("I like java and Python.")
print(m)
执行结果:
<re.Match object; span=(7, 22), match='Java and Python'>
<re.Match object; span=(7, 22), match='JAVA and Python'>
<re.Match object; span=(7, 22), match='java and Python'>