2015-6-8-python正则表达式模块的使用

时间:2022-10-02 22:34:20

0. 前言

发现自己在使用python的正则模块的时候,经常忘记具体的使用方法,搜索的话很快能得到解答,但过不了一阵就又忘记,而官方API文档有时候查找也是个麻烦。所以也就写个备忘,按照用途来归纳一下网上有的一些使用RE模块的经验。注意,本篇不讲述基本概念
首先当然是要

import re

1. 用法

1.1 先compile后match

适用于模式需要多次使用

p = re.compile('ab*')# p:re.RegexObject
p.match("abbbb")#将返回一个 MatchObject

compile方法可以接受一些标志常量作为第二个参数,例如re.IGNORECASE
返回的MatchObject可以做进一步操作:

方法/属性 作用
group() 返回被 RE 匹配的字符串
start() 返回匹配开始的位置
end() 返回匹配结束的位置
span() 返回一个元组包含匹配 (开始,结束) 的位置

具体效果用一次就知道。

1.2 直接匹配

如果模式不需要多次使用,直接匹配即可:

re.match(patternString, text)#返回的是MatchObject

这些模块级函数的基本用法与RegexObject几乎一致,只是需要传入一个pattern参数,不再赘述。

1.3 match与search

只有在字符串的开头开始匹配,match才会返回MatchObject对象,而search则在全text中寻找匹配。例如

line = "Cats are smarter than dogs";

#No match!!
matchObj = re.match( r'dogs', line, re.M|re.I)
if matchObj:
   print "match --> matchObj.group() : ", matchObj.group()
else:
   print "No match!!"# if line="dogs are smarter than cats", things change

#search --> matchObj.group() : dogs
searchObj = re.search( r'dogs', line, re.M|re.I)
if searchObj:
   print "search --> searchObj.group() : ", searchObj.group()
else:
   print "Nothing found!!"

1.4 特殊符号

特殊符号主要是.,\,$,^等具有特殊意义的符号,这些符号的一般用法我不予介绍,在第2节的规则图中都有说明,本小节只介绍特殊用法。

'\'
反斜杠在正则表达式中用于转义。同时注意,在python的字符串中反斜杠同样用于转义,所以反斜杠会经过两层解释:python字符串解释,正则表达式解释。
这可能导致一些意料之外的问题,例如想在Latex文本中匹配\section,它作为RE表达式,需要写成'\\section'转义反斜杠,同时,如果它直接作为字符串参数传入RE模块,则还要分别对这两个反斜杠转义,写成'\\\\section',显然这不漂亮。
一种便捷的方式是使用raw字符,这可以免去字符串转义,写成r'\\section'。但是注意,这时候所有字符串中的特殊转义就无用了,r'\n'将被识别为一个'\'和一个'n'
另一种就是老老实实用compile。

'.'
点号,如果指定了 DOTALL 标记,匹配包括换行符在内的任意一个字符。

'^'
尖号,在MULTILINE 模式下,将匹配任意一个新行的开始。

'$'
dollar符号,匹配一个字符串的结尾或者字符串最后面的换行符,在MULTILINE模式下,匹配任意一行的行尾。也就是说,普通模式下,foo.$去搜索'foo1\nfoo2\n'只会找到'foo2',但是在 MULTILINE 模式,还能找到 'foo1',而且就用一个 $去搜索'foo\n'的话,会找到两个空的匹配:一个是最后的换行符,一个是字符串的结尾,演示:

>>> re.findall('(foo.$)', 'foo1\nfoo2\n')
['foo2']
>>> re.findall('(foo.$)', 'foo1\nfoo2\n', re.MULTILINE)
['foo1', 'foo2']
>>> re.findall('($)', 'foo\n')
['', '']

*?, +?, ??
'*''+''?'都是贪婪的,但这也许并不是我们所要的。可以在后面加个问号,将策略改为非贪婪,只匹配尽量短的RE。示例,体会两者的区别:

>>> re.findall('<(.*)>', '<H1>title</H1>')
['H1>title</H1']
>>> re.findall('<(.*?)>', '<H1>title</H1>')
['H1', '/H1']

{m,n}?
{m,n},也是贪婪的,a{3,5}如果有5个以上连续a的话,会匹配5个,这个也可以通过加问号改变。a{3,5}?如果可能的话,将只匹配3个a。
(?…)
这是一个表达式的扩展符号。’?’后的第一个字母决定了整个表达式的语法和含义,除了(?P…)以外,表达式不会产生一个新的组。如果需要指定匹配模式或者需要对匹配起别名以便提取,可以使用这个符号。

\b
匹配单词边界(包括开始和结束),这里的“单词”,是指连续的字母、数字和下划线组成的字符串。注意,\b的定义是\w和\W的交界,所以精确的定义有赖于UNICODE和LOCALE这两个标志位。

\B
和\b相反,\B匹配非单词边界。
\b\B零宽界定符(zero-width assertions)

前向界定符(lookahead assertion)
前向界定符也是一种零宽界定符(zero-width assertion)。前向界定符包括前向肯定界定符和前向否定界定符,如下所示:
(?=...)
前向肯定界定符。如果所含正则表达式(以 ... 表示)在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎并不会停止,模式的剩余部分还要尝试匹配界定符的右边。
(?!...)
前向否定界定符。与肯定界定符相反,当所含表达式不能在字符串当前位置匹配时成功,模式的剩余部分继续参与匹配。
文字描述可能不太好理解,看例子
要求匹配所有文件扩展名不为bat的文件,包括.ba,.batch等。

.*[.](?!bat$).*$

使用了前向否定界定,当bat$匹配失败时,当前位置不移动,继续匹配后面的表达式,当bat$匹配成功时,当前位置失败,停止匹配并返回。
前向否定的意思:在当前位置向前看(前向),如果表达式 bat$ 不会被匹配,尝试模式的其余部分(当做没有这个表达式,当前位置不变);如果 bat$ 匹配,整个模式将失败(否定)。后面的 $ 是为了确保象 “sample.batch” 这样以 “bat” 开头的扩展名会被允许。

2. 正则表达式的规则

一图胜千言
2015-6-8-python正则表达式模块的使用

3. 字符串操作

RegexObject提供一些方法来对字符串进行操作。

方法/属性 作用
split(string [, maxsplit = 0]) 将字符串在 RE 匹配的地方分片并生成一个列表
sub(replacement, string[, count = 0]) 找到 RE 匹配的所有子串,并将其用一个不同的字符串替换
subn(replacement, string[, count = 0]) 与 sub() 相同,但返回新的字符串和替换次数

replacement中可以使用逆向引用,与正则匹配规则一样,字符串中的转义符号例如\n会被解释为对应的控制符,r'\n'则不会。
需要了解更多的方法可以查看官方文档

4. reference

比较详细Python正则表达式操作指南(re使用)
python正则表达式re模块详细介绍
Python正则表达式
Python正则表达式的七个使用范例
【循序渐进学Python】12.Python 正则表达式简介
Python doc
Python中使用正则表达式