Python 使用标准库的 re 模块支持正则表达式匹配。该模块的主要内容包括:
函数:
- match(pattern, string, flags=0) 从 string 开头匹配 pattern,返回一个匹配对象(match object)或 None
- search(pattern, string, flags=0) 在 string 里查找 pattern 的第一次出现,返回一个匹配对象 或 None
- findall(pattern, string, flags=0) 在 string 里查找 pattern 的所有非重复出现,返回一个包含所有结果的列表
- finditer(pattern, string, flags=0) 同 findall(),不过返回的是一个可迭代对象而非列表
- compile(pattern, flags=0) 预编译正则表达式 pattern,返回一个模式对象(pattern object),也叫正则表达式对象(regex)
- split(pattern, string, maxsplit=0, flags=0) 功能类似于 str 类型的 split 方法,但因可以使用模式对象而更强大
- sub(pattern, repl, string, count=0, flags=0) 功能类似于 Word 的查找替换功能,返回替换后的字符串
- subn(pattern, repl, string, count=0, flags=0) 功能同 sub(),但返回一个包含了替换后字符串和替换处数量的元组
匹配对象(match object)的方法(属性):
-
.group([index1[,index2...]]) 有index给出时,返回对象的子组字符串,多参数时返回元组。没index时同 .string 属性
-
.string 属性 同 .group() 方法无index参数时的结果,即返回一个总的匹配字符串
-
.groups([default=None]) 返回由全部子组组成的元组
模式对象(pattern object)的方法(属性):
'findall', 'finditer', 'flags', 'groupindex', 'groups', 'match', 'pattern', 'scanner', 'search', 'split', 'sub', 'subn'
功能与 re 模块内的函数相同,这里不再列举
元字符:
符号 | 说明 | 举例 |
literal | 字面量 | foo |
re1|re2 | re1或re2 | foo|bar |
. | 任何字符(换行符除外) | a.c |
^ | 字符串的开始 | ^Hello |
$ | 字符串的结尾 | to be continued$ |
* | 前面的表达式0或多次 | [0-9]* |
+ | 前面的表达式1或多次 | [a-z]+ |
? | 前面的表达式0或1次 | [A-Z]? |
{N} | 前面的表达式N次 | [0-9]{3} |
{M,N} | 前面的表达式M到N次 | [0-9]{1,3} |
[...] | 字符组中的任何一个 | [abcde] |
[...M-N...] | M到N中的任何一个 | [0-9a-zA-Z] |
[^...] | 不匹配此字符组中的任何一个 | [^aeiou] |
(...) | 匹配括号中的表达式并保存为子组 | (foo) |
(*|+|?|{}) ? | 当可重复时尽可能少匹配 | [0-9]+? |
特殊字符 | 说明 | 举例 |
\d | 任何数字,等同[0-9] | \d |
\D | 任何非数字,\d反义词,等同[^0-9] | \D |
\w | 任何数字和字母,等同[A-Za-z0-9],\W是反义词 | \w |
\s | 任何空白字符,等同[\n\t\r\f\v],\S是反义词 | Hello\sWorld |
\b | 单词的边界,\B是反义词 | \bThe\b |
\nn | 已保存的子组 | price: \16 |
\ | 转义字符,表示后面的符号自身(去除特殊意义) | \. |
\A | 字符串的起始,\Z是结束 | to be continued\Z |
除了上面罗列的这些,还有一些更高级的语法,比如 (?...)系列 。详情可参考官方文档:http://docs.python.org/3.3/library/re.html#regular-expression-syntax
个别内容解释:
\b
\bthe | 以“the”开始的字符串 |
\bthe\b | 单词“the” |
\Bthe | 包含“the”但不以之开头 |
()
小括号的作用有两个,一是可以把多个单字符组合起来使用“重复操作符”装饰,比如 foo+ 匹配的是 fo 和 o+ 的组合,但(foo)+ 匹配的则是整个 'foo' 重复至少一次的组合。括号的另一个作用是创建子组。
(*|+|?|{}) ?
这个操作符看起来有点乱,其重点其实是最后的那个“?”。它连接在重复操作符的后面,表示此重复操作符应当匹配“尽可能少”的字符。说尽可能少是因为重复操作符可以匹配的模式长度是不定的,比如 '\d+' 这个表达式如果遇到 '123' 这个字符串,那么它匹配出 '1', '12', '123' 都是对的。这种情况下 re 模块遵循的原则是“贪心算法”,即尽可能多的匹配,所以前面的例子会返回 '123' 。而如果在表达式的重复操作符(比如例子里的 '+')后面再加一个“?”,它就会选择最少的一种匹配模式,这时前面的例子会返回 '1' 。
所以,拿 \d 来举例:'\d+?' 等效于 '\d';'\d*?' 等效于 '',即空字符, 就是说 '\d*?' 实际什么都匹配不上。那么这个“?”到底有什么作用呢,它其实比较典型的应用是在“连续的重复匹配”操作上,用以避免“贪心算法”可能带来的副作用。比方说,对于‘hao123’这个字符串,我们想把‘123’匹配出来,如果写成‘(\w+)(\d+)’的话,贪心算法返回的子组是‘hao12’和‘3’。而若写成‘(\w+?)(\d+)’的话,就可以返回‘hao’和‘123’了。
>>> re.match('(\w+?)(\d+)','hao123').groups()
('hao', '123')
>>> re.match('(\w+)(\d+)','hao123').groups()
('hao12', '3')
匹配对象的 .group() 和 .groups() 方法
group() 方法或者返回所有匹配对象或是根据要求返回某个特定子组。groups() 则很简单,它返回一个包含唯一或所有子组的元组。如果正则表达式中没有子组的话, groups() 将返回一个空元组,而 group() 仍会返回全部匹配对象。
split() 函数(方法)
本函数和 str.split() 方法功能类似,都是分割字符串用的,不过这里可以使用一个模式对象而非字符串来做分割符,这点略强:
>>> 'www.baidu.com'.split('.')
['www', 'baidu', 'com']
>>> re.split('[()]','节(xi)哀(wen)顺(le)变(jian)')
['节', 'xi', '哀', 'wen', '顺', 'le', '变', 'jian', '']
在使用 split 时要注意可能产生的空字符串 '' 。