Python 正则匹配re模块
正则表达式简介
正则表达式(RegExp) 是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(元字符)。为了使文章更具可读性,本文将正则表达式冗长的语法介绍放在了文章的末尾。
运算符的优先级
正则表达式运算符的优先级顺序由高到低依次为:
-
转义符:
\ -
括号和中括号:
(),(?:),(?=),[] -
限定符:
*,+,?,{n},{n,},{n,m} -
定位点和序列:
^,$,\元字符,字符 -
替换:
|
字符具有高于替换运算符的优先级,使得 m|food 匹配 m 或 food。若要匹配 mood 或 food,请使用括号创建子表达式,即 (m|f)ood 。
Raw String
正则表达式使用反斜杠 \ 来代表特殊形式或用作转义字符,这里跟 Python 的语法冲突,因此,Python 只好用 \\\\ 匹配 \,因为正则表达式中如果要匹配 \,需要用\ 来转义,变成 \\ ,而 Python 语法中又需要对字符串中每一个 \ 进行转义,所以就变成了 \\\\ 。
为了使正则表达式具有更好的可读性,Python 特别设计了 Raw String。Raw String 以 r 作为字符串的前缀,如 r"\n" 表示字符 \ 和 n。
- 并非所有的正则表达式都需要使用 Raw String,但 compile 方法必须以 r 作为字符串的前缀;
- 对于其他方法(如 match、search 等 )而言,是否以 r 作为字符串的前缀并不影响结果。
re 模块简介
re 模块提供了 Perl 风格的正则表达式模式。Perl 5 对标准正则表达式增加了几个附加功能,re 模块也支持其中的大部分。
正则表达式对象
compile(RegExp [, flags]) 可以把正则表达式编译成一个正则表达式对象。其中,RegExp 为正则表达式,flags 为编译标志。
import re
html = re.compile(r"<\s*(\S+)(\s[^>]*)?>[\s\S]*<\s*/\1\s*>") # 匹配 HTML 标记(1)
编译标志
编译标志控制表达式的匹配方式。多个标志可以通过 | 来指定,如 re.I | re.M被设置成 I 和 M 标志。
| 标志 | 含义 |
|---|---|
| S 或 DOTALL |
使 . 匹配包括换行在内的所有字符
|
| I 或 IGNORECASE | 使匹配对大小写不敏感 |
| L 或 LOCALE | 做本地化识别匹配 |
| M 或 MULTILINE |
多行匹配,影响 ^ 和 $
|
| X 或 VERBOSE | 提高正则表达式的可读性 |
X 标志的作用:
-
不在字符集中的空白字符将被忽略。这使得:
dog | cat和可读性差的dog|cat相同,但[a b]将匹配字符 a、b 或空格。 -
可以把注释放到正则表达式当中。注释从
#开始到行末结束。
Xhtml = re.compile(r'''# 匹配 HTML 标记(2)
<\s*(\S+)(\s[^>]*)?> # 开始标签
[\s\S]* # 标签内的文本
<\s*/\1\s*> # 同名结束标签
''', re.X) # 同样匹配 HTML 标记,方法(2)的可读性比(1)高了很多。
执行匹配
| 方法 | 用途 |
|---|---|
match(RegExp, string [, flags])
|
从字符串的 开始 匹配一个模式,成功则返回 MatchObject 实例,否则返回 None |
search(RegExp, string [, flags])
|
在整个字符串内查找模式匹配,成功则返回 MatchObject 实例,否则返回 None |
findall(RegExp, string [, flags])
|
获取所有匹配的子串,并把它们作为一个列表返回 |
finditer(RegExp, string [, flags])
|
获取所有匹配的子串,并把它们作为一个迭代器返回 |
若已将正则表达式 RegExp 编译成了正则表达式对象 RegPat,还可以使用 RegPat.match(string) 执行匹配。
string = '''Hello World!\n<ul class="nav">
<li class="inactive"> 云 </li>
<li class="inactive"> 大数据 </li>
</ul>
'''
match_1 = re.match("\s\S*",string)
match_2 = re.match("\S*",string)
search_1 = re.search("\s\S*",string)
search_2 = Xhtml.search(string)
print(match_1, "\n", match_2, end = "\n-------------\n ")
print(search_1, "\n",search_2)
Output:
None
<_sre.SRE_Match object; span=(0, 5), match='Hello'>
-------------
<_sre.SRE_Match object; span=(5, 12), match=' World!'>
<_sre.SRE_Match object; span=(13, 99), match='<ul class="nav">\n\t<li class="inactive"> 云 </li>>
MatchObject 实例
| 方法 | 用途 |
|---|---|
group()
|
返回匹配的字符串 |
start()
|
返回匹配开始的位置 |
end()
|
返回匹配结束的位置 |
span()
|
返回一个二元元组: (开始位置,结束位置) |
print(search_2.group())
Output:
<ul class="nav">
<li class="inactive"> 云 </li>
<li class="inactive"> 大数据 </li>
</ul>
修改字符串
| 方法 | 用途 |
|---|---|
split(RegExp, string [, maxsplit = 0])
|
将字符串在匹配的位置分片,并生成一个列表;若 maxsplit 非零,则只能得到 maxsplit 个分片 |
sub(RegExp, replacement, string[, count = 0])
|
找到所有匹配的子串,并用其它的字符串替换;若 count 非零,则最多执行 count 次替换 |
subn(RegExp, replacement, string)
|
与 sub 类似,但返回二元元组:(新的字符串,执行替换的次数) |
print(re.split("\n",string)) # 用回车符分片
print(re.sub("\t", lambda m: '[' + m.group() + ']', string)) # 将制表符用 [ ] 括起来
Output:
['Hello World!', '<ul class="nav">', '\t<li class="inactive"> 云 </li>', '\t<li class="inactive"> 大数据 </li>', '</ul>', '']
Hello World!
<ul class="nav">
[]<li class="inactive"> 云 </li>
[]<li class="inactive"> 大数据 </li>
</ul>
正则表达式的基本语法
\ :将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如, n 匹配字符 n, \n 匹配 \n。序列 \\ 匹配 \ , \( 匹配 ( 。
^ :匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性, ^ 还会与 \n 或 \r 之后的位置匹配。
$ :匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性, $ 还会与 \n 或 \r 之前的位置匹配。
* :零次或多次匹配前面的字符或子表达式。例如, zo* 匹配 z 和 zoo 。 * 等效于 {0,} 。
+ :一次或多次匹配前面的字符或子表达式。例如, zo+ 与 zo 和 zoo 匹配,但与 z 不匹配。 + 等效于 {1,} 。
? :零次或一次匹配前面的字符或子表达式。例如, do(es)? 匹配 do 或 does 中的 do 。 ? 等效于 {0,1} 。
{n} :n 是非负整数。正好匹配 n 次。例如, o{2} 与 Bob 中的 o 不匹配,但与 food 中的两个 o 匹配。
{n,} :n 是非负整数。至少匹配 n 次。例如, o{2,} 不匹配 Bob 中的 o ,而匹配 food 中的所有 o。 o{1,} 等效于 o+ 。 o{0,} 等效于 o* 。
{n,m} :M 和 n 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。例如, o{1,3} 匹配 fooooood 中的头三个 o。 o{0,1} 等效于 o? 。
? :当此字符紧随任何其他限定符( * 、 + 、 ? 、 {n} 、 {n,} 、 {n,m} )之后时,匹配模式是非贪心的。非贪心的模式匹配搜索到的,尽可能短的字符串,而默认的贪心模式匹配搜索到的,尽可能长的字符串。例如,在字符串 oooo 中, o+? 只匹配单个 o,而 o+ 匹配所有 o。
. :匹配除 \n 之外的任何单个字符。若要匹配包括 \n 在内的任意字符,请使用诸如[\s\S] 之类的模式。
(pattern) :匹配 pattern 并捕获该匹配的子表达式。可以使用 \num 对捕获子表达式进行反向引用。括号 ( ) 使用 \( 或者 \) 匹配 。
(?:pattern) :匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用 | 组合模式部件的情况很有用。例如, industr(?:y|ies) 是比 industry|industries 更经济的表达式。
(?=pattern) :执行正向预测先行搜索的子表达式,该表达式匹配处于匹配 pattern 的字符串的起始点的字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如, Windows (?=95|98|NT|2000) 匹配 Windows 2000 中的 Windows ,但不匹配 Windows 3.1 中的 Windows 。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。
(?!pattern) :执行反向预测先行搜索的子表达式,该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如, Windows (?!95|98|NT|2000) 匹配 Windows 3.1 中的 Windows ,但不匹配 Windows 2000 中的 Windows 。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。
x|y :匹配 x 或 y。例如, z|food 匹配 z 或 food 。 (z|f)ood 匹配 zood 或 food 。
[xyz] :字符集。匹配包含的任一字符。例如, [abc] 匹配 plain 中的 a 。
[^xyz] :反向字符集。匹配未包含的任何字符。例如, [^abc] 匹配 plain 中的 p 。
[a-z] :字符范围。匹配指定范围内的任何字符。例如, [a-z] 匹配 a 到 z 范围内的任何小写字母。
[^a-z] :反向范围字符。匹配不在指定的范围内的任何字符。例如, [^a-z] 匹配任何不在 a 到 z 范围内的任何字符。
\b :匹配一个字边界,即字与空格间的位置。例如, er\b 匹配 never 中的 er ,但不匹配 verb 中的 er 。
\B :非字边界匹配。 er\B 匹配 verb 中的 er ,但不匹配 never 中的 er 。
\cx :匹配 x 指示的控制字符。例如, \cM 匹配 Control-M 或回车符。 x 的值必须在 A-Z 或 a-z 之间。否则假定 \c 就是 c 字符本身。
\d :数字字符匹配。等效于 [0-9] 。
\D :非数字字符匹配。等效于 [^0-9] 。
\f :换页符匹配。等效于 \x0c 和 \cL 。
\n :换行符匹配。等效于 \x0a 和 \cJ 。
\r :匹配一个回车符。等效于 \x0d 和 \cM 。
\s :匹配任何空白字符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v] 等效。
\S :匹配任何非空白字符。与 [^ \f\n\r\t\v] 等效。
\t :制表符匹配。与 \x09 和 \cI 等效。
\v :垂直制表符匹配。与 \x0b 和 \cK 等效。
\w :匹配任何字类字符,包括下划线。与 [A-Za-z0-9_] 等效。
\W :与任何非单词字符匹配。与 [^A-Za-z0-9_] 等效。
\xn :匹配 n ,此处的 n 是一个十六进制转义码。十六进制转义码必须是两位数长。例如, \x41 匹配 A 。允许在正则表达式中使用 ASCII 代码。
\num :匹配 num ,此处的 num 是第 num 个捕获子表达式的反向引用。例如,(.)\1 匹配两个连续的相同字符。
\n : 标识一个八进制转义码或反向引用。如果 \n 前面至少有 n 个捕获子表达式,那么是反向引用。如果 n 是八进制数 0-7,那么是八进制转义码。
\nm :标识一个八进制转义码或反向引用。如果 \nm 前面至少有 nm 个捕获子表达式,那么是反向引用。如果 \nm 前面至少有 n 个捕获,则是反向引用,后面跟有字符 m。如果两种前面的情况都不存在,则 \nm 匹配八进制值 nm,其中 n 和 m 是八进制数 0-7。
\nml :当 n 是八进制数 0-3, m 和 l 是八进制数 0-7 时,匹配八进制转义码 nml。
\un :匹配 n ,其中 n 是以四位十六进制数表示的 Unicode 字符。例如, \u00A9 匹配版权符号 ©。
示例1:
def test_regx():
content = ''' <div class="actifl"><h2>www.mimvp.com</h2></div> '''
import re
regx=r'<div class="actifl">(.*?)<h2>(?P<title>.*?)</h2>'
pattern = re.compile(regx,re.U|re.S|re.M|re.I)
match1 = pattern.match('<div class="actifl"><h2>www.mimvp.com</h2></div>')
print("countent: " + content)
print("match1: %r" % (match1, ))
print("match1: " + str(match1.span()))
print("match1: %r" % (match1.group(2).title()))
运行结果:
countent: <div class="actifl"><h2>www.mimvp.com</h2></div>
match1: <_sre.SRE_Match object at 0x7fa639582ad0>
match1: (0, 42)
match1: 'Www.Mimvp.Com'
示例2:
def test_regx2():
content = '<div class="actifl"><h2>www.mimvp.com</h2></div> '
import re
regx=r'<div class="actifl"><h2>(.*)</h2></div>'
pattern = re.compile(regx, re.U|re.S|re.M|re.I)
# match1 = pattern.match('<div class="actifl"><h2>www.mimvp.com</h2></div>') # ok
match1 = pattern.match(content)
print("countent: " + content)
print("match1: %r" % (match1, ))
print("match1: " + str(match1.span()))
print("match1: %r" % (match1.group(1)))
运行结果:
countent: <div class="actifl"><h2>www.mimvp.com</h2></div>
match1: <_sre.SRE_Match object at 0x7fa3eafaaf30>
match1: (0, 48)
match1: 'www.mimvp.com'
示例3(网页):
def test_regx3():
try:
req = urllib2.Request('https://blog.mimvp.com')
content = urllib2.urlopen(req).read()
content = content.decode('utf-8')
import re
regx=r'<title>(.*?)</title>' # <title> </title>
pattern = re.compile(regx,re.U | re.S)
match1 = pattern.findall(str(content))
# print("countent: " + content)
result = match1[0].decode('utf-8')
print("match1: %s" % result) # 米扑博客
except Exception, ex:
print("test_regx3() -- error_msg: " + str(ex))
运行结果:
match1: 米扑博客
参考推荐:
re正则表达式、BeautifulSoup、lxml 性能对比
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2018-09-13 13:00:08
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!
转载注明: Python 正则匹配re模块 (米扑博客)