正则表达式(RE)为高级文本模式匹配,以及搜索-替代等功能提供了基础。
Python通过标准库的re模块支持正则表达式(RE)
>>> import re
《python核心编程(第二版)》书中443页记录了常见的正则表达式符号和字符
表15.1 正则表达式中常见的符号和字符
| 记号 | 说明 | 正则表达式样例 |
| literal
| 匹配字符串的值 | foo
|
| re1|re2
| 匹配正则表达式re1或re2 | foo|bar
| #竖线
| .
| 匹配任何字符(换行符除外)(空字符除外) | b.b
| #点号
| ^
| 匹配字符串的开始 | ^Dear
| #上尖角号
| $
| 匹配字符串的结尾 | /bin/*sh$
| #美元符号
| *
| 匹配前面出现的正则表达式零次或多次 | [A-Za-z0-9]*
| #星号
| +
| 匹配前面出现的正则表达式一次或多次 | a-z[]+\.com
| #加号
| ?
| 匹配前面出现的正则表达式零次或一次 | goo?
| #问号
| {N}
| 匹配前面出现的正则表达式N次,指定N这个数量 | [0-9]{3}
| #大括号中间加一个数字
| {M,N}
| 匹配前面出现的正则表达式M次到N次 | [0-9]{5,9}
| #大括号中间加两个数字,中间用逗号分隔
| [...]
| 匹配字符组里面出现的任意一个字符 | [aeiou]
| #中括号中加字符
| [..x-y..]
| 匹配从字符x到y中的任意一个字符,“-” | [0-9]或[A-Za-z]
|
| [^...]
| 不匹配此字符集中出现的任何一个字符,包括某一个范围的字符(如果在此字符集中出现) | [^aeiou]
| #在中括号的内部的字符开头加上上尖角号
| (*|+|?|{})?
| 用于上面出现的任何匹配方式进行“非贪婪”形式匹配,即以最少的重复匹配次数 | .*?[a-z]
|
| ..(...)..
| 匹配出现的正则表达式(RE),匹配成功后括号当中的内容保存为子组,即只输出括号当中的内容 | ([0-9]{3})?或f(oo|u)bar
|
几种特殊字符
| \d
| 匹配任何数字,和[0-9]作用相同(\D是\d的反义:表示匹配任何非数字字符) | data\d或data\d+.txt
|
| \w
| 匹配任何数字字母字符,和[A-Za-z0-9_]作用相同(\W是\w的反义) | [A-Za-z_]\w+
|
| \s
| 匹配任何空白符,和[\n\t\r\v\f]作用相同,(\S是\s的反义) | of\sthe
|
| \b
| 匹配单词边界(\B是\b的反义) | \bThe\b
|
| \
| 逐一匹配特殊字符(即,取消该特殊字符的特殊含义,值按照字面匹配) | \.或\\或\*
|
| \A
| 匹配字符串的起始 | \ADear
|
| \Z
| 匹配字符串的结束 | Dear\Z
|
模块的函数:comple()
re模块的函数和regex对象的方法:
match(),search(),finditer() - 这两个函数需要利用正则表达式模式pattern匹配字符串,并利用匹配对象的方法group()或groups()输出字符结果
而findall(),split(),sub()通过可直接输出匹配的字符
compile(pattern, flags=0)
作用:对正则表达式模式pattern进行编译,flags是可选标识符,并返回一个regex对象。
主要用法:对要进行匹配的表达式进行编译后,可加快匹配寻找的速度,同时对于同一个表达式在后面的匹配过程中无序多次书写。
例子:
>>> tel=re.compile(r'\d{3,4}-?\d{8}')
#这个表达式的作用是匹配固话电话号码,前面数字3位加横线,加后面数字8位;compile的作用是对该正则表达式进行编译。
>>> tel
#编译后的对象
<_sre.SRE_Pattern object at 0x0263EBD0>
>>> tel.findall('010-12345678')
#编译对象的不同方法,比如findall方法可应用,与常规的re.findall(re.findall(r'\d{3,4}-?\d{8}', '010-12345678')
)方法不同之处在于,利用的是compile对象进行寻找。
['010-12345678']
>>> tel.match('010-12345678').group()
#同样的re.match方法也可应用
'010-12345678'
写法:
group(num=0):返回全部匹配对象(或指定编号的num子组)(num表示第几个子组)
groups():返回一个包含全部匹配的子组的元组(如果没有成功匹配,就返回一个空元组)
group()方法返回匹配对象是根据要求返回某个特定子组;而groups()会返回一个包含唯一或所有子组的元组。如果正则表达式中没有子组的话,groups()将返回一个空元组;而group()则会返回全部匹配对象。
相比于groups(),而group()的方法更为全面,不仅能够返回匹配对象,而且能够制定的返回子组,而groups()只负责返回子组,不负责返回匹配对象,这一点是重要区别
例子:
>>> m=re.match(r'(\w\w\w)-(\d\d\d)', 'abc-123')
#这里匹配前三个字母加横线加后三个数字
>>> m.group()
#group()输出全部的匹配结果,能够匹配则结果全部输出
'abc-123'
>>> m.group(1)
#括号当中的数字,表示输出第几个子组,1表示第一个子组
'abc'
>>> m.group(2)
#2表示第二个子组
'123'
>>> m.groups()
#将匹配的两个子组全部输出为一个元组
('abc', '123')
如果要匹配的表达式当中不存在子组,则group()返回匹配对象,groups()返回空元组
>>> m=re.match(r'\w\w\w-\d\d\d', 'abc-123')
>>> m.group()
'abc-123'
>>> m.groups()
()
match(pattern, string, flags=0)
用正则表达式模式pattern匹配字符串string,flags是可选标识符,如果匹配成功,返回一个匹配对象,匹配失败返回None
match的匹配特定是从字符串string的开头进行匹配,一旦要匹配的字符串在匹配模式中间时,匹配会失败
例子:
>>> re.search('foo', 'barfoo')
#要匹配的’foo’在’barfoo’字符串的中间,所以没有输出结果
>>> re.match('foo', 'bar')
无结果,如果输出re.match('foo', 'bar').group()
则会出现AttributeError: 'NoneType' object has no attribute 'group'
报错信息
如果想避免报错可以写成如下形式:
>>> m=re.match('foo', 'bar')
>>> if m is not None: m.group()
>>>
search(pattern, string, flags=0)
在字符串string中搜索正则表达式模式pattern的第一次出现,flags是可选的标识符,如果匹配成功,则返回一个匹配对象;否则返回None
search()搜索字符串中的模式首次出现的位置,而非从起始处进行匹配,所以match是匹配,而search是搜索,所以search得到的结果比较多。
例子:
>>> re.search('foo', 'barfoo')
<_sre.SRE_Match object at 0x0209FAA0>
>>> re.search('foo', 'barfoo').group()
'foo'
findall(pattern, string[, flags])
在字符串string中搜索正则表达式模式pattern的所有(非重复)出现,最终结果返回一个匹配对象的列表;如果没有找到匹配结果则返回一个空列表
例如:
>>> re.findall('car', 'car')
['car']
>>> re.findall('car', 'scary')
['car']
>>> re.findall('car', 'carry the barcard to the car')
['car', 'car', 'car']
当正则表达式存在多个子组时,匹配的返回结果是一个元组的列表,元组中每个元素都是一个子组的匹配内容,每一个匹配的列表构成列表元组,而当正则表达式存在一个子组时,则直接返回想要子组内容的匹配结果。
例子:
>>> re.findall('(ab)','ab')
#匹配内容只存在一个子组,直接返回想要子组内容的匹配结果
['ab']
>>> re.findall('(ab)((cd)(e))','abcde ab cd e')
#匹配ab,cd,e,cde
[('ab', 'cde', 'cd', 'e')]
>>> re.findall('(ab)','abcde ab cd e')
#匹配内容只存在一个子组,直接返回想要子组内容的匹配结果
['ab', 'ab']
>>> re.findall('(a(b))','abcde ab cd e')
#匹配ab,b
[('ab', 'b'), ('ab', 'b')]
sub(pattern, repl, string, max=0)
sub()和subn()可进行字符串内容的替换;sub()返回替换后的内容,而subn()则返回替换后的内容和次数,内容和次数构成一个元组
sub('s1', 'str2', 'string3')
s1
表示原字符串要被替换的内容
str2
表示替换后的内容
string3
表示要替换的字符串,即原始字符串
例子:
>>> re.sub('[ae]', 'X', 'abcdef')
#表示将字符串’abcdef’中的字母’a’和’e’均替换成’X’
'XbcdXf'
>>> re.subn('[ae]', 'X', 'abcdef')
#2是替换了两次
('XbcdXf', 2)
另外注意:re.sub当中的空格,不能用\s表示,如果想把\n替换成空格会失败,所以可用’ ‘(空格)来替换’\n’
>>> re.sub('\n', '\s', 'attnX\nDearX\naa')
'attnX\\sDearX\\saa'
>>> re.sub('\n', ' ', 'attnX\nDearX\naa')
'attnX DearX aa'
split(pattern, string, max=0)
根据正则表达式pattern中的分隔符把字符string分割为一个列表,返回成功匹配的列表,最多分割max次(默认是分割所有匹配的地方)
>>> re.split(':', 'str1:str2:str3')
#可以按照’:’这个字符来分隔
['str1', 'str2', 'str3']
>>> re.split('\d', 'str1:str2:str3:')
#也可以按照’\d’这个表达式分隔
['str', ':str', ':str', ':']
“?”操作符,表示“非贪婪”匹配,该操作可用在“*”,“+”或“?”等字符的后面,所用是要求正则表达式匹配的字符数量越少越好。
例如:
>>> data='4-6-8117159036'
>>> pattern=re.compile('(\d+-\d+-\d+?)')
#+表示前面的字符重复1到多次,而加入“?”则希望只重复一次
>>> pattern.findall(data)
['4-6-8']
>>> pattern_long=re.compile('(\d+-\d+-\d+)')
#没有“?”,则希望尽可能多的重复
>>> pattern_long.findall(data)
['4-6-8117159036']
| 标识 | 含义 |
| re.S
| 使“.”或“*”等能够匹配包括换行符在内的所有字符 |
| re.I
| 匹配不区分大小写 |
| re.L
| 做本地化识别(locale-aware)匹配 |
| re.M
| 可进行多行匹配,这样操作会影响“^”和“$”这两个符号的作用 |
| re.X
| 同样表示多行匹配,可应用于三引号当中的字符 |
实例:re.S
>>> re.findall(r'cctv.net', 'cctv\nnet')
[]
>>> re.findall(r'cctv.net', 'cctv\nnet', re.S)
['cctv\nnet']
#加入re.S标识后,“.”能够匹配换行符
实例:re.M
>>> s="""
hell world
world hello
hello world hello
world hehe
"""
>>> s
'\nhell world\nworld hello\nhello world hello\nworld hehe\n'
>>> re.findall(r'^world', s)
[]
>>> re.findall(r'^world', s, re.M)
['world', 'world']
#如果不加入re.M这个标识,“^”只运行单行匹配,但此时s为一个单一的字符串,加入re.M标识后,则运行“^”进行多行匹配。
实例:re.I
>>> re.findall(r'acd', 'AcdAAAcDC')
[]
>>> re.findall(r'acd', 'AcdAAAcDC', re.I)
#匹配不区分大小写
['Acd', 'AcD']
实例:re.X
>>> tel=r"""
\d{3,4}
-?
\d{8}
"""
>>> tel
'\n\\d{3,4}\n-?\n\\d{8}\n'
>>> re.findall(tel, '010-12345678')
[]
>>> re.findall(tel, '010-12345678', re.X)
['010-12345678']
re.X与re.M的作用基本相同,区别在于re.M用于要匹配的字符串内出现换行符,将每个换行符分隔开看做不同的行;而re.X用于匹配的正则表达式内出现的换行符,并且在进行匹配时忽视这些换行符。