Python教学课程分享4-正则表达式
正则表达式与re模块
正则表达式是处理字符串强大的工具,拥有独特的语法和独立的处理引擎,所以它还是有它的优势之处的。它还是一个特殊字符序列,能帮助用户检查一个字符串是否与某种模式匹配,从而达成快速检索或替换符合某个模式、规则的文本。例如,可以在文档中使用一个正则表达式表示特定文字。
re模块使Python语言拥有全部的正则表达式功能。compile函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象,该对象拥有一系列方法用于正则表达式匹配和替换。re模块提供与compile的函数功能完全一致的函数,这些函数使用模式字符串作为第一个参数。
4.5.1 正则表达式基本语法
正则表达式由元字符及其不同组合来构成,通过巧妙地构造正则表达式可以匹配任意字符串并且可以完成复杂的字符串处理任务。常用的正则表达式元字符有许多,如表4.3 常用的正则表达式元字符表所示:
表4.3 常用的正则表达式元字符表
元字符 |
功能 |
. |
匹配除换行符外的任意单个字符 |
* |
匹配位于“*”之前的字符或者子模式的0次或多次出现 |
+ |
匹配位于“+”之前的字符或者子模式的1次或多次出现 |
- |
用在[]之内用来表示范围 |
| |
匹配位于‘|’之前或之后的字符 |
^ |
匹配行首,匹配以^后面的字符开头的字符串 |
$ |
匹配行尾,匹配以$之前的字符结束的字符串 |
? |
匹配位于“?”之前的0个或1个字符。当次字符紧跟随任何其他限定符之后时,匹配模式为“非贪心的”。“非贪心模式”匹配搜索到的,尽可能短的字符串,而默认的“贪心的”模式匹配搜索到的,尽可能长的字符串。 |
\ |
表示位于\之后的为转义字符 |
\num |
此处的num是一个正整数 |
\f |
换页符匹配 |
\n |
换行符匹配 |
\r |
匹配一个回车符 |
\b |
匹配单词头或者单词尾 |
\B |
与\b含义相反 |
\d |
匹配任何数字,相当于[0-9] |
\D |
与\d含义相反,相当于[^0-9] |
\s |
匹配任何空白字符,包括空格,制表符,换页符,与[\f\n\r\t\v]等效 |
\S |
与\s含义相反 |
\w |
匹配任何字母,数字以及下划线,相当于[a-z,A-Z,0-9] |
\W |
与\w含义相反,与[^A-Z,a-z,0-9]等效 |
() |
将位于()内的内容作为一个整体来对待 |
{} |
按{}中的次数进行匹配 |
[] |
匹配位于[]中的任意一个字符 |
[^xyz] |
^放在[]内表示反向字符集,匹配除x、y、z之外的任何字符 |
[a-z] |
字符范围,匹配指定范围内的任何字符 |
[^a-z] |
反向范围字符,匹配除小写英文字母之外的任何字符 |
4.5.2 贪婪模式与非贪婪模式
贪婪模式与非贪婪模式影响的是被量词修饰的子表达式的匹配行为。贪婪匹配模式在整个表达式匹配成功的前提下,会尽可能多的向右对字符串进行遍历,继续进行匹配来查看是否还有更长的可以成功匹配的子串,即令正则表达式趋于最大长度匹配。
以源字符串‘aa<div>test1</div>bb<div>test2</div>cc’为例,如果用贪婪模式来匹配源字符串,结果为<div>test1</div>bb<div>test2</div>。而在非贪婪匹配模式下,在整个表达式匹配成功的的前提下,系统会以最少的匹配字符来进行匹配。仍是就上个源字符串举例,利用非贪婪模式进行匹配的话,当仅进行一次匹配结果输出时,输出结果为<div>test1</div>,并且如果没有命令指示不会进行回溯匹配。所以在一般情况下用非贪婪模式进行字符串的全部检测的话,对字符串进行回溯检查的次数是比贪婪模式要多的。
在Python语言结构中,默认的就是贪婪模式,如果在量词后面直接加上了一个问号(?)就是非贪婪模式。非贪婪模式只能被部分NFA引擎所支持。
从语法角度看贪婪与非贪婪模式的话,当遇到被匹配优先量词修饰的子表达式时,应该使用的是贪婪模式;而在遇到被忽略优先量词修饰的子表达式时,应该使用非贪婪模式。匹配优先量词包括:“{m,n}”、“{m,}”、“?”、“*”和“+”。忽略优先量词包括:“{m,n}?”、“{m,}?”、“??”、“*?”和“+?”。
从应用角度看,贪婪模式与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配;而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配。
从匹配原理角度看这两者,能达到同样匹配结果的贪婪与非贪婪模式,通常是贪婪模式的匹配效率较高。所有的非贪婪模式,都可以通过修改量词修饰的子表达式,转换为贪婪模式。贪婪模式可以与固化分组结合,提升匹配效率,而非贪婪模式却不可以。
4.5.3 re.match()、re.search()
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none;如果匹配成功的话则返回一个匹配的对象。它的指令格式如下:
l re.match(pattern, string, flags=0)
pattern为待匹配的正则表达式;string为想要对其进行匹配的字符串,flags=0的意义是标志位,用于控制正则表达式的匹配方式,比如是否区分大小写,多行匹配等等。同时还可以将这个指令与group(num)函数或者groups()函数来配合使用。group(num)函数的作用是匹配的整个表达式的字符串,可以在函数体内一次性输入多个组号,在这种情况下它将返回一个包含那些组所对应的元组。groups()函数则用来返回一个包含所有小组字符串的元组,范围为从1到所含的小组号。示例代码如下:
#!/usr/bin/python
import re line = "Cats are smarter than dogs"
Kee = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)
if Kee:
print "Kee.group() : ", Kee.group()
print "Kee.group(1) : ", Kee.group(1)
print "Kee.group(2) : ", Kee.group(2)
else:
print "No match!!"
输出结果为:
Kee.group() : Cats are smarter than dogs
Kee.group(1) : Cats
Kee.group(2) : smarter
re.search()函数方法的功能为扫描整个字符串并返回第一个成功的匹配。如果匹配成功,此函数方法会返回一个匹配的对象,如果匹配不成功则返回None。它的指令语法格式如下:
l re.search(pattern, string, flags=0)
用下面这段代码来展示它是如何在环境中使用的。示例代码如下:
#!/usr/bin/python
import re
line = "Cats are smarter than dogs"
Kee = re.search( r'(.*) are (.*?) .*', line, re.M|re.I)
if Kee:
print("Kee.group() : ", Kee.group())
print("Kee.group(1) : ", Kee.group(1))
print("Kee.group(2) : ", Kee.group(2))
else:
print("Nothing found!!")
输出结果为:
Kee.group() : Cats are smarter than dogs
Kee.group(1) : Cats
Kee.group(2) : smarter
关于flag标志位,主要有以下几种表达形式,如表4.4 正则表达式修饰符-可选标志表。
表4.4 正则表达式修饰符-可选标志表
修饰符 |
功能 |
re.l |
使匹配对大小写不敏感 |
re.L |
做本地化识别匹配 |
re.M |
多行匹配,影响^和$ |
re.S |
使.匹配包括换行在内的所有字符 |
re.U |
根据Unicode字符集进行字符解析。这个标志影响\w,\W,\b,\B |
re.X |
该标志通过给予更灵活的格式以便使用者将正则表达式写的更易于理解 |
4.5.4 re.split()
split() 函数按照能够匹配的子串将字符串分割后返回列表,它的指令格式如下:
l re.split(pattern, string[, maxsplit, flags=0])
在上面的表达式中,maxsplit为分隔次数,默认为零,不限制此数,当此数为1时表示分隔1次。其他参数含义同上。关于split()函数的示例如下:
>>> import re
>>> re.split('\W+', ' runoob, runoob, runoob.', 1)
['', 'runoob, runoob, runoob.']
>>> re.split('a*', 'hello world') #若找不到匹配的字符串,split 不会对其作出分割
['hello world']
4.5.5 re.sub()
sub()函数提供一个替换值,可以是字符串或函数,和一个要被处理的字符串。在它的命令中,会将字符串中的所有pat的匹配项用rep项替换掉。同时需要注意的是,返回的字符串是在字符串中用最左边的不重复的匹配来替换。如果模式没有被发现,字符将没有被改变的返回。并且可选参数count是模式匹配后替换的最大次数,它必须是一个非负整数,当缺省值为零时表示替换所有的匹配。
l sub(pat,rep,string[,count =0 ])
关于sub()函数的示例代码如下:
>>> import re
>>> Kee = re.compile('blue|white|red')
>>> m = Kee.sub('colour','blue socks and red shoes')
>>> print(m)
'colour socks and colour shoes'