在做文字处理或编写程序时,用到查找、替换等功能,使用正则表达式能够简单快捷地完成目标。正则表达式通过一些特殊符号的帮助,使用户可以轻松快捷地完成查找、删除、替换等处理程序。例如 Linux 系统中的 grep, expr, sed, awk 等高级命令都离不开正则表达式。正规表示法基本上是一种『表示法』, 只要工具程序支持这种表示法,那么该工具程序就可以用来作为正规表示法的字符串处理之用。
本节内容仅涉及 Python 中使用正则表达式的常规操作,这些操作可以应对绝大多数正则表达式的使用场景。本节内容不会使用常见的陈列一堆令初学者眼晕的正则符号及其说明的形式,而是一步一步地,以可以直接动手操作的形式讲述。大家只需按照课程文档的步骤进行操作并稍作思考,即可快速掌握正则表达式的基本套路。
正则表达式是一个特殊的字符序列,从对象字符串中匹配它,可以获得想要的字符串片段。切记,正则表达式不需要背,熟练操作即可。
首先,引入 re
,在 Python 中,使用该模块来写正则表达式:
>>> import re
要获取某个字符或字符串,使用 findall
方法可以获取全部能够匹配的片段,放到一个列表里。findall
方法第一个参数为正则表达式,规定匹配规则,第二个参数为被匹配对象,下文将大量使用该方法。
普通字符
下面代码中的参数 "hello"、"实验楼"、"o" 均为普通字符/字符串:
>>> s = 'hello shiyanlou, 你好实验楼'
>>> re.findall('hello', s)
['hello']
>>> re.findall('实验楼', s)
['实验楼']
>>> re.findall('o', s)
['o', 'o']
元字符
-
\d
获取所有数字 0 - 9 -
\D
匹配所有非数字 -
\w
匹配所有单词字符,包括大小写字母、数字、下划线、中文 -
\W
匹配剩下的,空格、换行符、特殊字符等:
>>> s = 'abc_004\nGT# 预言'
>>> re.findall('\d', s)
['0', '0', '4']
>>> re.findall('\D', s)
['a', 'b', 'c', '_', '\n', 'G', 'T', '#', ' ', '预', '言']
>>> re.findall('\w', s)
['a', 'b', 'c', '_', '0', '0', '4', 'G', 'T', '预', '言']
>>> re.findall('\W', s)
['\n', '#', ' ']
字符集
顾名思义,就是字符的集合,用中括号表示 [ ]
,它匹配任意一个符合条件的字符。字符集内 ^
表示 “非”,它只能在字符集内被使用;字符集外 ^
在模式的开始处使用,表示需要在行的开始处进行匹配,后面会讲到。
因此,\d
等于 [0-9]
,\D
就等于 [^0-9]
。注意:\w
不等于 [a-zA-Z_0-9]
,因为后者不能匹配中文。
具体用法举例:
>>> s = 'char_achar_b, char_cpythonchar_d正则#'
>>> re.findall('char_[ad]', s)
['char_a', 'char_d']
>>> re.findall('char_[^ad]', s)
['char_b', 'char_c']
>>> re.findall('char_[a-c]', s) # a-c 表示 a 至 c
['char_a', 'char_b', 'char_c']
>>> re.findall('[^0-9a-zA-Z_]', s)
[',', ' ', '正', '则', '#']
>>> re.findall('[^\w]', s)
[',', ' ', '#']
空白字符
空白字符共有这四种:' '
空格、\n
换行符、\t
制表符、\r
回车符,使用元字符 \s
匹配它们,自然 \S
匹配任意非空白字符:
>>> s = '楼+ \nPython\t'
>>> re.findall('\s', s)
[' ', '\n', '\t']
>>> re.findall('[^\s]', s)
['楼', '+', 'P', 'y', 't', 'h', 'o', 'n']
>>> re.findall('\S', s)
['楼', '+', 'P', 'y', 't', 'h', 'o', 'n']
数量符号和特殊数量符号
使用大括号 {}
标定匹配字符的数量。默认的匹配模式为贪婪模式,即选取尽可能多的匹配字符;?
表示非贪婪模式,即选取最少的匹配字符,所以 {3, 6}?
就等同于 {3}
:
>>> s = 'linux,python-git123'
>>> re.findall('[a-z]{3}', s)
['lin', 'pyt', 'hon', 'git']
>>> re.findall('[a-z]{3,6}', s)
['linux', 'python', 'git']
>>> re.findall('[a-z]{3,6}?', s)
['lin', 'pyt', 'hon', 'git']
特殊数量符号:
-
*
匹配任意数量的字符 -
?
匹配 0 或 1 个字符,这也是它可以设置非贪婪模式的原因。也就是说,所谓的非贪婪,只是被设定为最多匹配 1 个的贪婪模式,贪婪是永恒的 -
+
匹配 1 个或多个字符 -
.
匹配除换行符\n
以外任意 1 个字符
注意:特殊数字符号控制的是紧挨着该符号左边的字符或字符集:
>>> s = 'hell#hello$helloo'
>>> re.findall('hello*', s) # 尽可能多地匹配任意数量的字符 "o"
['hell', 'hello', 'helloo']
>>> re.findall('hello?', s)
['hell', 'hello', 'hello']
>>> re.findall('hello+', s)
['hello', 'helloo']
>>> re.findall('H.', 'Hello')
['He']
>>> re.findall('H.', 'H\nello') # "." 不能匹配换行符
[]
边界字符
在模式的开始处使用 ^
表示需要在行的开始处进行匹配。例如 ^abc
可以匹配 abc123
但不匹配 123abc
。
在模式的末尾处使用 $
表示需要在行的末端进行匹配。例如 abc$
可以匹配 123abc
但不能匹配 abc123
。
简单的例子:
>>> s = 'hello world'
>>> re.findall('wo', s)
['wo']
>>> re.findall('^wo', s)
[]
>>> re.findall('.*lo', s)
['hello']
>>> re.findall('.*lo$', s)
[]
字符组
把任意数量的字符用小括号 ()
括起来,就是字符组,目的是为匹配成功的字符串进行分组。findall
方法会匹配第一个参数的正则表达式并过滤掉字符组外面的字符,保留小括号内的部分:
>>> s = ' 实验楼 Python\n'
# \w 不能匹配 “楼” 和 "P" 中间的空格,所以结果为两个成功匹配的字符串
>>> re.findall('\s*(\w+)\s*', s)
['实验楼', 'Python']
>>> re.findall('\s*(.+)\s*', s)
['实验楼 Python']
模式参数
findall
方法还有第三个参数,模式参数。下面介绍两个较为常用的:re.I
忽略大小写,re.S
匹配空白字符。多个模式参数用 |
隔开,举例说明:
>>> s = 'Hello\nWorld'
>>> re.findall('Lo', s) # 不能匹配 "L"
[]
>>> re.findall('Lo', s, re.I) # re.I 忽略大小写
['lo']
>>> re.findall('Lo.', s, re.I) # "." 不能匹配换行符
[]
>>> re.findall('Lo.', s, re.I | re.S) # re.S 匹配任意空白字符,包括换行符
['lo\n']
另一个常见的模式参数 re.M
,多行模式,如果字符串中有换行符 \n
,把字符串看成多行,这么做的话,对于那些匹配行首行尾的表达式,情况就不一样了,举个例子:
In [57]: s
Out[57]: 'hello\nhell'
In [58]: re.findall('^he.*', s)
Out[58]: ['hello']
In [59]: re.findall('^he.*', s, re.M)
Out[59]: ['hello', 'hell']
总结
本节实验讲解了 Python 正则表达式的基本规则,能够满足日常大多数使用场景。当然正则还有更为复杂的规则,各个语言、系统之间在使用正则表达式时也有微小的差异,re
模块还有其它比较实用的方法来利用正则表达式,例如 compile
、match
、sub
等,希望大家通过本节课程讲解的知识,在需要时可以很容易地自学掌握其它复杂的规则和方法。