正则表达式为高级的文本模式匹配、抽取、与/或文本形式的搜索和替换功能提供了基础。正则表达式是一些由字符和特殊符号组成的字符串,它们描述了模式的重复或者表述多个字符,能按照某种模式匹配一系列有相似特征的字符串。Python通过re模块来支持正则表达式,需要注意的是,Python中有两种方法完成模式匹配:search()和match()。search是在字符串人一部分中搜索匹配的模式;而match是判断一个字符串能否从起始处全部或者部分地匹配某个模式。
特殊符号和字符
即元字符
使用择一匹配符号匹配多个正则表达式模式
“|”表示一个“从多个模式中选择其中之一”的操作,用于分割不同的正则表达式。例如:
择一匹配有时也被称为并或者逻辑或。
匹配任意单个字符
“.”表示匹配除了换行符\n以外的任何字符,如果要匹配句号浮点本身则必须使用反斜线转义句点符号的功能,例如"\."。
从字符串起始或者结尾或者单词边界匹配
“^”或者“\A”表示匹配字符串开始位置;“$”或者“\Z”表示匹配字符串末尾位置。
“\b”和“\B”用于匹配字符边界。区别在于\b将用于匹配一个单词的边界,这意味着如果一个模式必须位于单词的起始部分,就不管该单词前面是否有任何字符。\B将匹配出现在一个单词中间的模式。
创建字符集
“[]”用于匹配一对方括号中包含的任何字符。
限定范围和否定
方括号中两个符号中间用连字符“-”连接,用于指定一个字符的范围,但仅仅只能限定用于字母和十进制数字。另外,如果脱字符“^”紧跟在左方括号后面,这个符号就表示不匹配给定字符集中的任何一个字符。
使用闭包操作符实现存在性和频数匹配
“*”、“+”、“?”用于匹配一个、多个或者没有出现的字符串模式(编译原理中称为闭包)
*:将匹配其左边的正则表达式出现零次或者多次的情况;
+:将匹配一次或多次出现的正则表达式,又称正闭包操作;
?:将匹配零次或一次出现的正则表达式;
“{}”,大括号里面或者是单个值或者是一对逗号分隔的值,这将最终精确地匹配前面的正则表达式N次(若果是{N})或者一定范围的次数,例如{M,N}将M~N次出现。
表示字符集的特殊字符
\d:表示匹配任何十进制数字;
\D:表示匹配任何非十进制数;
\w:能够用哦勾玉表示全部字母数字的字符集,相当于[A-Za-z0-9];
\s:可以用来表示空格字符;
使用圆括号指定分组
我们很多时候不仅想要知道整个字符串是否匹配,还想知道能否提取任何已经成功匹配的特定字符串或字符子串。此时就需要使用到圆括号。
一对圆括号可以实现以下任意一个(或者两个)功能:
- 对正则表达式进行分组
- 匹配子组
圆括号进行分组的一个副作用就是,匹配模式的子字符串可以保存起来供后续使用。
扩展表示法
以?开始,通常用于在判断匹配之前提供标记,实现一个前视或者后视,或者条件检查。
正则表达式和Python语言
下表列出了re模块的常见函数和方法
使用compile()函数编译正则表达式
compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。语法格式为:
re.compile(pattern[, flags])
参数:
pattern : 一个字符串形式的正则表达式
flags : 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
- re.I 忽略大小写
- re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
- re.M 多行模式
- re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
- re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
- re.X 为了增加可读性,忽略空格和 # 后面的注释
说白了就是将一个正则表达式字符串转化为一个re对象。
使用match()方法匹配字符串
match()识图从字符串的起始部分对模式进行匹配。如果匹配成功,就返回一个匹配对象;如果匹配失败,就返回None,匹配对象的group()方法能够用于显示那个成功的匹配。
函数语法:
re.match(pattern, string, flags=0)
函数参数说明:
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串。 |
flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。参见:正则表达式修饰符 - 可选标志 |
匹配成功re.match方法返回一个匹配的对象,否则返回None。
我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
匹配对象方法 | 描述 |
---|---|
group(num=0) | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。 |
groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。 |
例如:
>>> import re
>>> m=re.match('foo','foo')
>>> if m is not None:
m.group()
'foo'
>>> m=re.match('foo','bar')
>>> if m is not None:
m.group()
注意:只要模式从字符串起始部分开始匹配,即使字符串比模式长,匹配也仍然能够成功。
使用search()在一个字符串中查找模式
search()扫描整个字符串,并返回第一次成功的匹配。
语法:
re.search(pattern, string, flags=0)
函数参数说明:
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串。 |
flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。 |
匹配成功re.search方法返回一个匹配的对象,否则返回None。
我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
匹配对象方法 | 描述 |
---|---|
group(num=0) | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。 |
groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。 |
例如:
>>> m=re.search('foo','seafood')
>>> if m is not None:
m.group()
'foo'
匹配多个字符串
“|”符号,用于匹配多个字符串
>>> import re
>>> bt='bat|bet|bit'
>>> m=re.match(bt,'bat')
>>> if m is not None:
m.group()
'bat'
>>> m=re.search(bt,'He bit me!')
>>> if m is not None:
m.group()
'bit'
匹配任何单个字符
在下列示例中,展示了“.”不能匹配一个换行符\n或者非字符,也就是说一个空字符串
>>> anyend='.end'
>>> m=re.match(anyend,'bend')
>>> if m is not None:
m.group()
'bend'
>>> m=re.match(anyend,'end') #匹配不成功
>>> if m is not None:
m.group()
>>> m=re.match(anyend,'\nend')
>>> if m is not None:
m.group()
在下列示例在正则表达式中搜索一个真正的句点,通过转义来匹配:
>>> patt314='3.14'
>>> pi_patt='3\.14'
>>> m=re.match(pi_patt,'3.14')
>>> if m is not None:
m.group()
'3.14'
>>> m=re.match(patt314,'3014')
>>> if m is not None:
m.group()
'3014'
>>> m=re.match(patt314,'3.14')
>>> if m is not None:
m.group()
'3.14'
创建字符集([ ])
>>> m=re.match('[cr][23][dp][o2]','c3po')
>>> if m is not None:
m.group()
'c3po'
>>> m=re.match('[cr][23][dp][o2]','c3do')
>>> if m is not None:
m.group()
'c3do'
>>> m=re.match('r2d2|c3po','c2do') #匹配不成功
>>> if m is not None:
m.group()
>>> m=re.match('r2d2|c3po','r2d2')
>>> if m is not None:
m.group()
'r2d2'
重复、特殊字符以及分组
正则表达式中最常见的情况包括特殊字符的使用、正则表达式模式的重复出现,以及使用圆括号对匹配模式的各个部分进行分组和提取操作。
“\w+”表示匹配任何字母至少一个
匹配字符串的起始和结尾以及单词边界
该操作多用于表示搜索而不是匹配,因为match()总是从字符串开始位置进行匹配的。
>>> m=re.search('^The','The end.') #匹配
>>> if m is not None:
m.group()
'The'
>>> m=re.search('^The','end. The') #不作为起始,匹配失败
>>> if m is not None:
m.group()
>>> m=re.search(r'\bthe','bite the hotdog') #在边界,r'xxxx'表示原生字符串,例如"\\xxxxx"可以写成r"\xxxxx"
>>> if m is not None:
m.group()
'the'
>>> m=re.search(r'\bthe','bitethe hotdog') #不在边界
>>> if m is not None:
m.group()
>>> m=re.search(r'\Bthe','bitethe hotdog') #没有边界,匹配成功
>>> if m is not None:
m.group()
'the'
使用findall()和finditer()查找每一次出现的位置
findall()查询字符串中某个正则表达式模式全部的非重复出现情况。这与search()在执行字符串搜索时类似,但与match()和search()不同之处在于,findall()总是返回一个列表。如果findall没有找到匹配的部分,就返回一个空列表,但如果匹配成功,列表将包含所有成功的匹配部分(从左向右按出现顺序排列)
>>> re.findall('car','car')
['car']
>>> re.findall('car','scary')
['car']
>>> re.findall('car','carry the barcardi to the car')
['car', 'car', 'car']
finditer()与findall()类似,但是更节省内存。两者之间以及和其他变体函数之间的差异在于,和返回的匹配字符串相比,finditer()在匹配对象中迭代。
使用sub()和subn()搜索与替换
这两种方法用于实现搜索和替换功能,两者几乎一样,都是将某字符串中所有匹配正则表达式的部分进行某种形式的替换。用来替换的部分通常是一个字符串,但它也可能会是一个函数,该函数返回一个用来替换的字符串,此外subn()还返回一个表示替换的总数,替换后的字符串和表示替换总数的数字一起作为一个拥有两个元素的元组返回。
>>> re.sub('X','Mr.Smith','attn:X\n\nDear X,\n')
'attn:Mr.Smith\n\nDear Mr.Smith,\n'
>>> re.subn('X','Mr.Smith','attn:X\n\nDear X,\n')
('attn:Mr.Smith\n\nDear Mr.Smith,\n', 2)
>>> re.sub('[ae]','X','abcdef')
'XbcdXf'
>>> re.subn('[ae]','X','abcdef')
('XbcdXf', 2)
在限定模式上使用split()分隔字符串
基于某个模式pat将字符串str分隔开split(pat,str),如果给定分隔符不是使用特殊符号来匹配多重模式的正则表达式,那么re.split()与str.split()的工作方式相同,如下所示(基于单引号分隔):
>>> re.split(':','str1:str2:str3')
['str1', 'str2', 'str3']