1.1简介
正则表达式是高级的文本模式匹配、抽取、或文本形式的搜索和替换功能提供了基础。正则表达式(简称regex)是由一些字符或特殊符号组成的字符串,他们描述了模式的重复或表述多个字符,于是正则表达式能够按照某一模式匹配一系列有相似特征的字符串。Python使用re模块来支持正则表达式。
符号 | 描述 |
---|---|
* | 匹配0次或者多次前面出现的正则表达式 |
+ | 匹配一次或者多次出现前面的正则表达式 |
? | 匹配0次或者1次前面出现的正则表达式 |
. | 匹配任何字符除了换行符 |
^ | 匹配字符串开始部分 |
$ | 匹配字符串结束部分 |
\d | 匹配任何十进制数字,与[0-9]一致 |
\w | 匹配任何字母数字字符 |
1.2 特殊符号和字符
限定范围与否定
字符集支持匹配指定的字符范围,方括号中两个符号中间用‘-’连接,用于指定一个字符的范围。例如:A-Z、a-z、或者0-9分别表示大写字母、小写字母、数字。如果脱字符‘^’紧跟左方括号后面,这个符号就表示不匹配给定字符集中的任何一个字符。例如‘[^aeiou]’表示一个非元音字符。
闭包操作符与贪婪匹配
闭包操作符指的是上文提到的.、*、?;除了这三个还有大括号操作符,里面是单个值或者是一对由逗号分离的值{M},{M,N},这将最终精确地匹配前面的正则表达式M次或者M到N次。
如果?号之前是非闭包操作符,这表示要么匹配0次要么匹配1次。
如果?号之前是闭包操作符,它将直接要求正则表达式引擎匹配尽可能少的次数。
当模式使用分组操作符时,正则表达式引擎试图吸收匹配该模式尽可能多的字符,这也就是贪婪匹配。
上文所说尽可能少的次数是说尽可能少的匹配字符,也就是非贪婪匹配。
使用圆括号进行分组
对正则表达式进行分组
匹配子组
1.3使用Python语言支持正则表达式
re.compile()
compile(pattern,flag=0):使用任何可选的标记来编译正则表达式的模式,然后返回一个正则表达式对象
经过预编译阶段,生成代码对象比直接使用的字符串要快,正则表达式在执行过程中将进行多次比较操作,因此建议预编译。
pattern = re.compile(r'([a-z]+) ([a-z]+)',re.I) #预编译
m = pattern.match('hello world python regex') #match方法
print(m.group(0)) #输出‘hello world’
group()
当处理正则表达式时,除了正则表达式对象外,还有一个对象类型:匹配对象。也就是成功调用match()和search()函数返回的对象。group()要么返回整个匹配对象,要么根据要求返回特定子组。
re.match()
match(pattern,string,flags=0)函数试图从字符串的起始部分对模式进行匹配,如果匹配成功,就返回一个匹配对象;如果匹配失败,返回None。
line = "Cats are 1 are smarter than dogs"
matchObj = re.match(r'(.*) are (.*?) .*', line, re.M | re.I) #re.I 不区分大小写标记
if matchObj:
print("matchObj.group() : ", matchObj.group()) #输出 Cats are 1 are smarter than dogs
print("matchObj.group(1) : ", matchObj.group(1)) #输出 Cats are 1 (贪婪匹配)
print("matchObj.group(2) : ", matchObj.group(2)) #输出 smarter (非贪婪匹配)
re.search()
search(pattern,string,flag=0)工作方式与match函数一致,不同之处在于search会用它的字符串参数,在任意位置对给定正则表达式模式搜索第一次出现的匹配情况,如果成功返回匹配,否则返回None
line = "Cats are smarter than dogs"
matchObj = re.match(r'dogs', line, re.M | re.I)
if matchObj:
print("match --> matchObj.group() : ", matchObj.group())
else:
print("No match!!") #True
matchObj = re.search(r'dogs', line, re.M | re.I)
if matchObj:
print("search --> matchObj.group() : ", matchObj.group()) #输出 dogs
else:
print("No match!!")
重复、特殊字符以及分组
正则表达式最常见的情况包括特殊字符的使用、正则表达式模式的重复出现,以及使用圆括号对匹配模式的各部分进行分组和提取操作。例如一个邮件的正则表达式:
‘\w+@\w+.com’
但是,假如添加了域名前的主机名称,例如www.xxx.com,改造后的正则表达式为:
‘\w+@(\w+.)?\w+.com’
接下来进一步扩展,允许任意数量的中间子域名存在
‘\w+@(\w+.)*\w+.com’
patt = '(\w\w\w)-(\d\d\d)'
m = re.match(patt,'abc-123')
print(m.group()) #输出 abc-123
print(m.group(1)) #输出 abc
print(m.group(2)) #输出 123
print(m.groups()) #输出 ('abc', '123')
findall和finditer
findall()函数查询字符串中某个正则表达式模式全部的非重复出现情况,与search()函数类似,但是findall()返回一个列表,如果没有匹配返回一个空列表。
finditer()函数与findall函数功能类似,但是更节省内存。
str = 'this and that'
print(re.findall('(th\w+)',str)) #输出 ['this', 'that']
it = re.finditer(r'(th\w+)',str)
#书中给出的是it.next(),Python3上提示有问题,参照如下修改
g = next(it)
print(g.groups()) #输出 ('this',)
print(g.group(1)) #输出 this
g = next(it)
print(g.groups()) #输出 ('that',)
sub()和subn()搜索和替换
这两个函数都是将某字符串中所有匹配正则表达式的部分进行某种形式的替换,用来替换的部分通常是一个字符串,或者是一个函数,函数返回一个用来替换的字符串。subn()还返回一个替换的总数,替换后的字符串和表示替换总数的数字一起作为一个拥有两个元素的元组返回。
sub(pattern, repl, string, count=0, flags=0):
其中repl代表替换字符串
m = re.sub('[ae]','zhang','abcdef')
print(m) #输出 zhangbcdzhangf
m = re.subn('[ae]','zhang','abcdef')
print(m) #输出 ('zhangbcdzhangf', 2)