Python 内置的字符串处理函数能够解决很多的字符串处理问题,但对于比较复杂的情况,内置的字符串可能无法处理,或者处理过程显得十分不优雅。为此,我们需要掌握更强大的文本处理工具 - 正则表达式。
比如,下面的例子,希望同时使用 .
和 :
作为分隔符切分字符串,就需要用到我们的正则表达式了:
>> import re
>> s = "10::29::30 root: 172.17.73.41 xxxxxxxxxxx"
>> re.split('[:.]+\s*', s)
['10', '29', '30 root', '172', '17', '73', '41 xxxxxxxxxxx']
正则表达式作为处理文本的强大工具,具有非常优秀的表达能力。想必熟悉 Linux 系统的用户可定对通配符很熟悉了,比如,列出文件名包含 .py
的所有文件:
mia@ubuntu:~$ ls -al *.py*
-rw-r--r-- 1 mia mia 220 Jun 30 08:31 mymode.py
-rw-r--r-- 1 mia mia 602 Jun 30 08:31 mymode.pyc
正则表达式的原理与通配符类似,只不过通配符能匹配的文本范围非常有限,而正则表达式功能更加强大,相应的也更加复杂。
不过,在工作中,很多时候我们只需要使用简单的正则表达式,配合 Python 内置的正则表达式处理函数,即可在拥有强大表达能力的同时,降低正则表达式使用的难度。
合抱之木,生于毫末。九层之台,起于垒土。本篇文章,我们就先来了解正则表达式的常用语法,连载的后续文章,将继续更新 Python 使用正则表达式的具体内容。
正则表达式好比工程师定义的过滤文本的模式。文本处理程序使用定义好的模式去过滤输入的文本,对于匹配模式的文本将会进一步处理,不匹配模式的文本将会被直接过滤。
因此,定义模式以及熟悉模式的定义规则是正则表达式的核心。正则表达式由 普通文本 和 具有特殊意义的符号 组成。比如,下面的例子中使用 [a-zA-Z]+
来匹配文本中的单词:
>> s = "1. Python 之禅中提到:Simple is better than complex."
>> re.findall('[a-zA-Z]+', s)
['Python', 'Simple', 'is', 'better', 'than', 'complex']
再比如,使用 [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}
来匹配 IP 地址:
>> s = "10::29::30 root: 172.17.73.41 xxxxxxxxxxx"
>> re.search('[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}', s)
上述的正则表达式匹配有点号分隔的 1 到 3 位数,其中 [0-9]
表示数字取值范围,{1,3}
表示重复前面字符 1 ~ 3 次。
另外,需要特别注意的是,.
在正则表达式中属于特殊字符,因此这里使用 \.
转义的方式来表示真正的点号运算。
下面,我们列出了正则表达式中最长使用的特殊符号及其含义:
正则表达式 | 描述 | 示例 |
---|---|---|
^ |
行起始标记 | ^import numpy 匹配 import numpy 开头的行 |
$ |
行尾标记 | import numpy$ 匹配 import numpy 结尾的行 |
. |
匹配任意一个字符 | - |
[] |
匹配包含在 [] 之中的任意字符 |
[pP]ython 匹配 python 和 Python |
[^] |
匹配 [^] 之外的任意一个字符 |
9[^56] 匹配 95 , 96 以外的 9x 文本 |
[-] |
匹配 [] 中指定范围内的任意一个字符 |
[0-9] 匹配 0~9 之间的任意一个数字;[a-z] 匹配 a~z 之间的任意一个字母 |
? |
匹配之前的项 0 次或 1 次 | hel? 匹配 he hel |
+ |
匹配之前的项 1 次或多次 | hel+ 匹配 hel hell ... |
* |
匹配之前的项 0 次或多次 | hel* 匹配 he hel hell ... |
{n} |
匹配之前的项 n 次 | [0-9]{3} 匹配任意一个 3 位数 |
{n,} |
匹配之前的项最少 n 次 | [0-9]{3,} 匹配任意一个 3 位数或更多的数字 |
{n,m} |
匹配之前的项 n ~ m 次 | [0-9]{2,5} 匹配 2 位数到 5 位数之间的任意一个数字 |
通过上表我们发现,正则表达式中 $
^
[
]
(
)
等诸多字符都有特别的含义。如果希望他们作为普通字符,则需要使用转义的方式使用。