正则表达式是处理字符串强大的工具,拥有独特的语法和独立的处理引擎,效率可能不如str自带的方法,但功能十分强大。
1、认识正则表达式
正则表达式是一个特殊字符序列,能帮助用户检查一个字符串是否与某种模式匹配,从而达成快速检索或替换符合某个模式、规则的文本。如:可以在文档中使用一个正则表达式表示特定文字,然后将其全部删除或替换成别的文字。
Python自1.5版本起增加了re模块,它提供了Perl风格的正则表达式模式,re模块使Python语言拥有全部的正则表达式功能。Compile函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象,该对象拥有一系列方法用于正则表达式匹配和替换。
re模块提供与compile的函数功能完全一致的函数,这些函数使用模式字符串作为第一个参数。
字符串是编程时涉及最多的数据结构,对字符串操作的需求几乎无处不在。
特殊字符类在正则表达式中的应用
实例 | 描述 |
---|---|
. | 匹配除“\n”之外的任何单个字符。要匹配包括‘\n’在内的任意字符,请使用如 ‘[.\n]’的模式 |
\d | 匹配一个数字字符,等价于[0-9] |
\D | 匹配一个非数字字符,等价于[^0-9] |
\s | 匹配任意空白字符,包括空格、制表符、换页符等,等价于 [\f\n\r\t\v] |
\S | 匹配任意非空白字符,等价于 [^\f\n\r\t\v] |
\w | 匹配包括下划线的任意单词字符,等价于 ‘[A-Za-z0-9 ]’ |
\W | 匹配任意非单词字符,等价于 ‘[^A-Za-z0-9 ]’ |
字符类在正则表达式中的应用
实例 | 描述 |
---|---|
[Pp]ython | 匹配 “Python” 或 “python” |
rub[ye] | 匹配 “ruby” 或 “rube” |
[aeiou] | 匹配中括号内的任意一个字母 |
[0-9] | 匹配任意数字,类似于 [0123456789] |
[a-z] | 匹配任意小写字母 |
[A-Z] | 匹配任意大写字母 |
[a-zA-Z0-9] | 匹配任意字母及数字 |
[^aeiou] | 除了aeiou字母以外的所有字符 |
[^0-9] | 匹配除了数字外的字符 |
例如:我们要判断一个字符串是否是合法的Email地址,可以用编程的方式提取@前后的子串,再分别判断是否是单词和域名。不过这样做不但需要写一堆麻烦的代码,而且写出来的代码难易重复使用,面对不同的需求可能需要使用不同的代码实现。
正则表达式是匹配字符串的强有力的武器。正则表达式的设计思路是用描述性语言为字符串定义一个规则,凡是符合规则的字符串,我们就认为“匹配”,否则就不匹配。正则表达式的大致匹配过程是:一次拿出表达式和文本中的字符比较,如果每一个字符都能匹配,匹配就成功,一旦有匹配不成功的字符,匹配就失败。
用正则表达式判断一个字符串是否是合法的Email的方法是:
- 创建一个匹配Email的正则表达式;
- 用该正则表达式匹配用户的输入从而判断是否合法;
在正则表达式中,如果直接给出字符,就是精确匹配。
- ‘00\d’可以匹配 ‘007’,但无法匹配 ‘00q’
- ‘\d\d\d’可以匹配 ‘123’
- ‘\w\w\d’可以匹配 ‘py3’
- . 可以匹配任意字符,所有 ‘py.’可以匹配 ‘pyc’ ‘pyo’ ‘py!’等
正则表达式中,要匹配变长的字符,用*表示任意个数的字符(包括0个),用+表示至少一个字符,用?表示0个或1个字符,用{n}表示n个字符,用{n,m}表示n~m个字符。
例如:\d{3}\s+\d{3,8} 该字符串从左到右解读为:
- \d{3}表示匹配3个数字,如 ‘010’ ;
- \s可以匹配一个空格(包括Tab等空白符),\s+表示至少有一个空格,如匹配 ‘ ’/ ‘ ’等;
- \d{3,8}表示3~8个数字,如 ‘1234567’
综上所述,正则表达式可以匹配以任意个数的空格隔开的带区号的电话号码。
如果要匹配 ‘010-12345’这样的号码呢?由于 ‘-’是特殊字符,在正则表达式中要用 ‘\’转义,因此用正则表达式表示为 \d{3}-\d{3,8}。
要更精确地匹配,可以用[ ]表示范围,例如:
- [0-9a-zA-Z_]用以匹配数字、字母或下划线,这种方式可以在一些场所做输入值或命名的合法性校验;
- [0-9a-zA-Z_]+可以匹配至少由一个数字、字母或下划线组成的字符串,如 ‘a100’ ‘0_Z’ ‘Py3000’。这种方式可以校验一个字符串是否包含数字、字母或下划线;
- [z-aA-Z_][0-9a-zA-Z_]*可以匹配由字母或下划线开头,后接任意个数字、字母或下划线组成的字符串,也就是Python的合法变量;
- [a-zA-Z_][0-9a-zA-Z_]{0,19}更精确的限制了变量的长度是1~20个字符(前面一个字符+后面最多19个字符);
- A|B用于匹配A或B,如(P|p)ython可以匹配 ‘Python’或 ‘python’;
- ^表示行的开头,^\d表示必须以数字开头;
- $表示行的结束,$表示必须以数字结束;
当我们在Python中使用正则表达式时,re模块内部会做两件事情:
- 编译正则表达式,如果正则表达式的字符串本身不合法,就会报错;
- 用编译后的正则表达式匹配字符串;
如果一个正则表达式需要重复使用上千次,处于效率的考虑,我们可以预编译该正则表达式,这样重复使用时就不需要编译这个步骤,直接匹配即可。
2、re模块
1)re.match()函数
一般使用re的步骤是先将正则表达式的字符串形式编译为Pattern实例,然后使用Pattern实例处理文本并获得匹配结果(一个match函数),最后使用match函数获得信息,进行其他的操作。
re.match函数尝试从字符串的起始位置匹配一个模式,该函数语法为:
re.match(pattern , string ,flags = 0)
pattern指匹配的正则表达式;string指要匹配的字符串;flags为标志位,用于控制正则表达式的匹配方式,如是否区分大小写、多行匹配等。
如果匹配成功,re.match方法就返回一个匹配的对象,否则返回None。
import re
print(re.martch(‘hello’ , ‘hello world’).span()) #在起始位置匹配
print(re.martch(‘world’ , ‘hello world’)) #在起始位置匹配
(0,5)
None
2)re.search()方法
在re模块中,除了match函数外,search方式也经常使用。
re.search方式用于扫描整个字符串并返回第一个成功匹配的字符。
re.rsearch(pattern , string , flags =0)
pattern指匹配的正则表达式;string指要匹配的字符串;flags为标志位,用于控制正则表达式的匹配方式,如是否区分大小写、多行匹配等。
如果匹配成功,re.search方式就返回一个匹配的对象,否则返回None。
import re
print(re.search(‘hello’ , ‘hello world’).span()) #在起始位置匹配
print(re.search(‘world’ , ‘hello world’).span()) #不在起始位置匹配
(0,5)
(6,11)
3)re.match()与re.search()的区别
re.match函数只匹配字符串开始的字符,如果开始的字符不符合正则表达式,匹配就会失败,函数返回None。
re.search方法匹配整个字符串,直到找到一个匹配的对象,匹配结束没找到匹配值才返回None。
import re
line = ‘Cats are smarter than dogs’
matchObj = re.match(r’dogs’ , line ,re.M|re.I)
if matchObj:
print(‘use match , the string is:’ , matchObj.group())
else:
print(“No match string!!”)
matchObj = re.search(r’dogs’ , line ,re.M|re.I)
if matchObj:
print(‘use search , the match string is:’ , matchObj.group())
else:
print(“No match string!!”)
No match string!!
use search , the match string is: dogs
该实例使用了match类中的分组方法 – group方法。该方法定义为:
def group(self , *agrs):
“”” Return one or more subgroups of the match.
:rtype:T|tuple
“””
psss
group([group1 , …]):获得一个或多个分组截获的字符串,指定多个参数时以元组的形式返回。group1可以使用编号,也可以使用别名。编号0代表整个匹配的子串。不填写参数时,返回group(0);没有截获字符串的组时,返回None;截获多次字符串的组时,就返回最后一次截获的子串。
还有一个常用的分组方法groups.
groups([default]):以元组形式返回全部分组截获的字符串,相当于调用group(1,2,…last)。default表示没有截获字符串的组以这个值代替,默认为None。
4)re.sub() 替换函数
Python 的re模板提供了re.sub,用于替换字符串中的匹配项。
sub(repl , string[ , count])|re.sub(pattern , repl , string[ , count]):使用repl替换string中每一个匹配的子串后返回替换后的字符串。当repl是一个方法时,这个方法应当只接受一个参数(match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。count用于指定最多替换次数,不指定时全部替换。
pt = re.compile(r’(w+)(w+)’)
greeting = ‘I say , hello world!’
peint(pt.sub(r’2 1’ , greeting))
def func(m):
return m.group(1).title() + ‘’ + m.group(2).title()
print(pt.sub(func , greeting))
I say ,hello world!
I say ,hello world!
5)re.split()分隔函数
re.split(string [ , maxsplit = 0])
在string中根据Pattern分隔,最多分maxsplit 次,maxsplit =0表示全部分开。
6)修饰符
正则表达式的修饰符:
以下修饰符在re.compile的第二个参数指定
默认全部关闭
通过 “|”启用多个修饰符
Try:
修饰符 | 全称 | 描述 |
---|---|---|
re.I | re.IGNORECASE | 匹配忽略大小写 |
re.L | re.LOCALE | 根据本地设置解释什么是word,主要影响词(\w和\W)和词边界(\b和\B) |
re.M | re.MULTILINE | 使$表示行结束(而不是字符串结束),使^表示行开始(而不是字符串开始) |
re.S | re.DOTALL | 使点号 . 可以匹配任何字符,包括换行符 |
re.U | re.UNICODE | 根据Unicode字符集解释字母,影响\w、\W、\b、\B |
re.X | re.VERBOSE | 智能表达式,忽略空格(除了[]中的)并把#当做注释 |
3、贪婪模式和非贪婪模式
正则表达式通常使用于查找匹配的字符串。Python里数量词默认是贪婪的,总是尝试匹配尽可能多的字符;非贪婪模式正好相反,总是尝试匹配尽可能少的字符。
例如:正则表达式 “ab*”如果用于查找 “abbbc”,就会找到 “abbb”。如果使用非贪婪的数量词 “ab*?”,就会找到 “a”。
print(re.match(r’^(\d+)(0*)$’ , ‘102300’).groups())
(‘102300’, ‘’)
由于\d+采用贪婪匹配,直接把后面的0全部匹配了,结果0*只能匹配空字符串。要让0*能够匹配到后面的两个0,必须让\d+采用非贪婪匹配(尽可能少匹配)。在0*后面的加一个“?”就可以让\d+采用非贪婪匹配。
print(re.martch(r’^(\d+?)(0*)$’ , ‘102300’).groups)
(‘1023’ , ‘00’)