简介
正则表达式(Regular expressions 也称为 REs,或 regexes 或 regex patterns)本质上是一个微小的且高度专业化的编程语言。它被嵌入到 Python 中,并通过 re 模块提供给程序猿使用。使用正则表达式,你需要指定一些规则来描述那些你希望匹配的字符串集合。这些字符串集合可能包含英语句子、 e-mail 地址、TeX 命令
注意:
Python 的正则表达式引擎是用 C 语言写的,所以效率是极高的。另,所谓的正则表达式,这里说的 RE,就是上文我们提到的“一些规则”。
字符匹配
大多数字母和字符会匹配它们自身。举个例子,正则表达式Dog 将完全匹配字符串 “Dog”,默认情况下区分大小写。当然这个规则也有例外。有少数特殊的字符我们称之为元字符(metacharacter),它们并不能匹配自身,它们定义了字符类、子组匹配和模式重复次数等。
元字符
下边是元字符的完整列表:
. ^ $ * + ? {
} [ ] \ | ( )
如果没有这些元字符,正则表达式就变得跟字符串的 find()
方法一样平庸了…
[ ]
下方括号 [ ],它们指定一个字符类用于存放你需要匹配的字符集合。可以单独列出需要匹配的字符,也可以通过两个字符和一个横杆 - 指定匹配的范围。例如 [abc]
会匹配字符 a,b 或 c;[a-c] 可以实现相同的功能。后者使用范围来表示与前者相同的字符集合。举例:如果你想只匹配小写字母,你的 RE 可以写成 [a-z]
注意:
元字符在方括号中不会触发“特殊功能”,在字符类中,它们只匹配自身。例如 [akm$]
会匹配任何字符 'a'
,'k'
,'m'
或 '$'
,'$'
是一个元字符,但在方括号中它不表示特殊含义,它只匹配 ‘$’ 字符本身。
你还可以匹配方括号中未列出的所有其他字符。做法是在类的开头添加一个脱字符号 ^ ,例如 [^5]
会匹配除了 ‘5’ 之外的任何字符
反斜杠\
跟 Python 的字符串规则一样,如果在反斜杠后边紧跟着一个元字符,那么元字符的“特殊功能”也不会被触发。例如你需要匹配符号 [
或 \
,你可以在它们前面加上一个反斜杠,以消除它们的特殊功能:\[,\\
反斜杠后边跟一些字符还可以表示特殊的意义,例如表示十进制数字,表示所有的字母或者表示非空白的字符集合。
反斜杠后边跟元字符去除特殊功能,反斜杠后边跟普通字符实现特殊功能。
举个例子:\w
匹配任何单词字符。如果正则表达式以字节的形式表示,这相当于字符类 [a-zA-Z0-9_]
;如果正则表达式是一个字符串,\w
会匹配所有 Unicode
数据库(unicodedata
模块提供)中标记为字母的字符。你可以在编译正则表达式的时候,通过提供 re.ASCII
表示进一步限制 \w
的定义。
re.ASCII
标志使得 \w
只能匹配 ASCII
字符,不要忘了,Python3
是 Unicode 的。
特殊字符 | 含义 |
---|---|
\d | 匹配任何十进制数字;相当于类 [0-9] |
\D | 与 \d 相反,匹配任何非十进制数字的字符;相当于类 [^0-9] |
\s | 匹配任何空白字符(包含空格、换行符、制表符等);相当于类 [ \t\n\r\f\v] |
\S | 与 \s 相反,匹配任何非空白字符;相当于类 [^ \t\n\r\f\v] |
\w | 匹配任何单词字符,见上方解释 |
\W | 于 \w 相反 |
\b | 匹配单词的开始或结束 |
\B | 与 \b 相反 |
它们可以包含在一个字符类中,并且一样拥有特殊含义。例如 [\s,.]
是一个字符类,它将匹配任何空白字符(/s
的特殊含义),','
或 '.'
。
.
另外一个元字符是 .
,它匹配除了换行符以外的任何字符。如果设置了 re.DOTALL
标志,.
将匹配包括换行符在内的任何字符。
*
我们来看看 *
这个元字符,当然它不是匹配 '*'
字符本身,它用于指定前一个字符匹配零次或者多次
例如 ca*t
将匹配 ct
(0 个字符 a),cat
(1 个字符 a
),caaat
(3 个字符 a),等等。需要注意的是,由于受到 C 语言的 int 类型大小的内部限制,正则表达式引擎会限制字符 'a'
的重复个数不超过 20 亿个。
正则表达式默认的重复规则是贪婪的,当你重复匹配一个 RE 时,匹配引擎会尝试尽可能多的去匹配。直到 RE 不匹配或者到了结尾,匹配引擎就会回退一个字符,然后再继续尝试匹配
通过例子一步步的给大家讲解什么叫“贪婪”:先考虑一下表达式 a[bcd]*b
,首先需要匹配字符 'a'
,然后是零个到多个 [bcd]
,最后以 ‘b’ 结尾。那现在想象一下,这个 RE 匹配字符串 abcbd
会怎样?
步骤 | 匹配 | 说明 |
---|---|---|
1 | a | 匹配 RE 的第一个字符 ‘a’ |
2 | abcbd | 引擎在符合规则的情况下尽可能地匹配 [bcd]* ,直到该字符串的结尾 |
3 | 失败 | 引擎尝试匹配 RE 最后一个字符 ‘b’,但当前位置已经是字符串的结尾,所以失败告终 |
4 | abcb | 回退,所以 [bcd]* 匹配少一个字符 |
5 | 失败 | 再一次尝试匹配 RE 最后一个字符 ‘b’,但字符串最后一个字符是 ‘d’,所以失败告终 |
6 | abc | 再次回退,所以 [bcd]* 这次只匹配 'bc' |
7 | abcb | 再一次尝试匹配字符 ‘b’,这一次字符串当前位置指向的字符正好是 ‘b’,匹配成功 |
RE 匹配的结果是 abcb
。
正则表达式默认的匹配规则是贪婪的,后边有说如何使用非贪婪的方法匹配。
+
要特别注意 *
和 +
的区别:*
匹配的是零次或者多次,所以被重复的内容可能压根儿不会出现;+
至少需要出现一次。例如 ca+t
会匹配 cat
和 caaat
,但不会匹配 ct
。
?
还有两个表示重复的元字符,其中一个是问号 ?
,用于指定前一个字符匹配零次或者一次。你可以这么想,它的作用就是把某种东西标志位可选的。例如 小?鱼 可以匹配 小鱼,也可以匹配 鱼。
{}
最灵活的应该是元字符 {m,n}
(m 和 n 都是十进制整数),上边讲到的几个元字符都可以使用它来表达,它的含义是前一个字符必须匹配 m 次到 n 次之间。例如 a/{1,3}b
会匹配 a/b
,a//b
和 a///b
。但不会匹配 ab
(没有斜杠);也不会匹配 ab
(斜杠超过三个)。
你可以省略 m 或者 n,这样的话,引擎会假定一个合理的值代替。省略 m,将被解释为下限 0;省略 n 则会被解释为无穷大(事实上是上边我们提到的 20 亿)。
如果是 {,n} 相当于 {0,n};如果是 {m,} 相当于 {m,+无穷};如果是 {n},则是重复前一个字符 n 次。另外还有一个超容易出错的是写成 {m, n},看着挺美,但注意,正则表达式里边不能随意添加空格,不然会改变原来的含义。
其实 *
、+
和 ?
都可以使用 {m,n}
来代替。{0,}
跟 *
是一样的;{1,}
跟 + 是一样的;{0,1}
跟 ?
是一样的。不过还是鼓励大家记住并使用 *
、+
和 ?
,因为这些字符更短并且更容易阅读。
还有一个原因是匹配引擎对 * + ?
做了优化,效率要更高些。