一、简介
- 正则表达式本质上是一门语言,它不从属与Python!Python只是将他人写好的正则引擎集成到了语言内部,大多数编程语言都是这么干的
- 正则表达式诞生的时间很长,应用非常广泛,是业界公认的字符串匹配工具。虽然有不同版本的内部引擎,但基本通用,也就是说,你在Python内写的正则表达式,可以移植到Linux的shell,Java语言等任何支持正则的场景中去
- 正则表达式默认从左往右匹配
- 正则表达式默认是贪婪模式
- 正则表达式默认在匹配到了内容后,则终止匹配,不继续匹配
- 对同一个问题,编写的正则表达式不是唯一的
二、语法
通用语法,和Python实现无关,核心:编写一个表达式字符串,用这个字符串匹配文本,所有字符均是英文状态下的字符
- 普通字符
- 字母、数字、汉子、下划线、以及没有特殊定义的符号,都是【普通字符】。正则表达式中的普通字符,在匹配的时候,只匹配与自身相同的一个字符
- 比如,表达式
<font style="color:#F5222D;">c</font>
,在匹配字符串<font style="color:#F5222D;">abcde</font>
时,匹配结果是:成功;匹配到的内容是<font style="color:#F5222D;">c</font>
;匹配到的位置开始于2,结束于3。
- 元字符
- 正则表达式中使用了很多元字符,用来表示一些特殊的含义或功能
表达式 | 匹配 | |
---|---|---|
<font style="color:#F5222D;">.</font> |
小数点可以匹配除了换行符<font style="color:#F5222D;">\n</font> 意外的任意一个字符 |
|
` | ` | 逻辑或操作符 |
<font style="color:#F5222D;">[]</font> |
匹配字符集中的一个字符 | |
<font style="color:#F5222D;">[^]</font> |
对字符集求反,也就是上面的反操作,符号必须在方括号的最前面 | |
<font style="color:#F5222D;">-</font> |
定义<font style="color:#F5222D;">[]</font> 里的一个字符区间,例如<font style="color:#F5222D;">[a-z]</font> |
|
<font style="color:#F5222D;">\</font> |
对紧跟其后的一个字符进行转义 | |
<font style="color:#F5222D;">()</font> |
对表达式进行分组,将圆括号内的内容当做一个整体,并获得匹配的值 |
例如:
<font style="color:#F5222D;">a.c</font>
匹配<font style="color:#F5222D;">abc</font>
<font style="color:#F5222D;">(a|b)c</font>
匹配<font style="color:#F5222D;">ac</font>
与<font style="color:#F5222D;">bc</font>
<font style="color:#F5222D;">[abc]1</font>
匹配<font style="color:#F5222D;">a1</font>
or<font style="color:#F5222D;">b1</font>
or<font style="color:#F5222D;">c1</font>
- 使用方括号
<font style="color:#F5222D;">[]</font>
包含一系列字符,能够匹配其中任意一个字符。用<font style="color:#F5222D;">[^]</font>
包含一系列字符,则能够匹配其中字符之外的任意一个字符 <font style="color:#F5222D;">[ab5@]</font>
匹配<font style="color:#F5222D;">a</font>
或<font style="color:#F5222D;">b</font>
或<font style="color:#F5222D;">5</font>
或<font style="color:#F5222D;">@</font>
<font style="color:#F5222D;">[^abc]</font>
匹配<font style="color:#F5222D;">a</font>
,<font style="color:#F5222D;">b</font>
,<font style="color:#F5222D;">c</font>
之外的任意一个字符<font style="color:#F5222D;">[f-k]</font>
匹配<font style="color:#F5222D;">f~k</font>
之间的任意一个字母<font style="color:#F5222D;">[^A-F0-3]</font>
匹配<font style="color:#F5222D;">A~F</font>
以及<font style="color:#F5222D;">0~3</font>
之外的任意一个字符
- 转义字符
一些无法书写或者具有特殊功能的字符,采用在前面加斜杠<font style="color:#F5222D;">'\'</font>
表达式 | 匹配 |
---|---|
<font style="color:#F5222D;">\r,\n</font> |
匹配回车和换行符 |
<font style="color:#F5222D;">\t</font> |
匹配制表符 |
<font style="color:#F5222D;">\\</font> |
匹配斜杠<font style="color:#F5222D;">\</font> |
<font style="color:#F5222D;">\^</font> |
匹配<font style="color:#F5222D;">^</font> 符号 |
<font style="color:#F5222D;">\$</font> |
匹配<font style="color:#F5222D;">$</font> 符号 |
<font style="color:#F5222D;">\.</font> |
匹配<font style="color:#F5222D;">.</font> 符号 |
尚未列出的还有问号<font style="color:#9254DE;">?</font>
、星号<font style="color:#9254DE;">*</font>
和括号<font style="color:#9254DE;">()</font>
等其他的符号。所有正则表达式中具有特殊含义的字符在匹配自身的时候,都要使用斜杠进行转义。这些转义字符的匹配方法与普通字符类似,也是匹配与之相同的一个字符。
<font style="color:#F5222D;">\$d</font>
,在匹配字符串<font style="color:#F5222D;">"abc$de"</font>
时,匹配结果是:成功;匹配到的内容是<font style="color:#F5222D;">$d</font>
;匹配到的位置开始于3,结束于5
- 预定义匹配字符集
<font style="color:#F5222D;">\d</font>
可以匹配任意一个数字。虽然可以匹配其中任意字符,但是只能是一个,不是多个。如下表所示,注意大小写:
表达式 | 匹配 |
---|---|
<font style="color:#F5222D;">\d</font> |
任意一个数字,<font style="color:#F5222D;">0~9</font> 中的任意一个 |
<font style="color:#F5222D;">\w</font> |
任意一个字母或数字或下划线,也就是<font style="color:#F5222D;">A~Z</font> ,<font style="color:#F5222D;">a~z</font>``,<font style="color:#F5222D;">0-9</font> 中的任意一个 |
<font style="color:#F5222D;">\s</font> |
空格、制表符、换页符等空白字符的其中任意一个 |
<font style="color:#F5222D;">\D</font> |
<font style="color:#F5222D;">\d</font> 的反集,也就是非数字的任意一个字符,等同于<font style="color:#F5222D;">[^\d]</font> |
<font style="color:#F5222D;">\W</font> |
<font style="color:#F5222D;">\w</font> 的反集,等同于<font style="color:#F5222D;">[^\w]</font> |
<font style="color:#F5222D;">\S</font> |
<font style="color:#F5222D;">\s</font> 的反集,等同于<font style="color:#F5222D;">[^\s]</font> |
<font style="color:#F5222D;">\d\d</font>
,在匹配<font style="color:#F5222D;">abc123</font>
时,匹配的结果是:成功;匹配到的内容是12;匹配到的位置开始于3,结束于5
- 重复匹配
<font style="color:#F5222D;">\d\d\d\d\d\d\d\d\d\d\d</font>
(注意,这不是一个恰当的表达式),不但写着费劲,看着也累,还不一定准确恰当
这种情况可以使用表达式再加上修饰匹配次数的特殊符号<font style="color:#F5222D;">{}</font>
,不用重复书写表达式就可以重复匹配。比如<font style="color:#F5222D;">[abcd][abcd]</font>
可以写成<font style="color:#F5222D;">[abcd]{2}</font>
| 表达式 | 匹配 |
| :—-: | —- |
| <font style="color:#F5222D;">{n}</font>
| 表达式重复n次,比如<font style="color:#F5222D;">\d{2}</font>
相当于<font style="color:#F5222D;">\d\d</font>
,<font style="color:#F5222D;">a{3}</font>
相当于<font style="color:#F5222D;">aaa</font>
|
| <font style="color:#F5222D;">{m,n}</font>
| 表达式至少重复<font style="color:#F5222D;">m</font>
次,最多重复<font style="color:#F5222D;">n</font>
次。比如<font style="color:#F5222D;">ab{1,3}</font>
可以匹配<font style="color:#F5222D;">ab</font>
或<font style="color:#F5222D;">abb</font>
或<font style="color:#F5222D;">abbb</font>
|
| <font style="color:#F5222D;">{m,}</font>
| 表达式至少重复m次,比如<font style="color:#F5222D;">\w\d{2,}</font>
可以匹配<font style="color:#F5222D;">a12</font>
,<font style="color:#F5222D;">_1111</font>
,<font style="color:#F5222D;">M123</font>
等等 |
| <font style="color:#F5222D;">?</font>
| 匹配表达式0次或者1次,相当于<font style="color:#F5222D;">{0,1}</font>
,比如<font style="color:#F5222D;">a[cd]?</font>
可以匹配<font style="color:#F5222D;">a,ac,ad</font>
|
| <font style="color:#F5222D;">+</font>
| 表达式至少出现1次,相当于<font style="color:#F5222D;">{1,}</font>
,比如<font style="color:#F5222D;">a+b</font>
可以匹配<font style="color:#F5222D;">ab</font>
,<font style="color:#F5222D;">aab</font>
,<font style="color:#F5222D;">aaab</font>
等等 |
| <font style="color:#F5222D;">*</font>
| 表达式出现0次到任意次,相当于<font style="color:#F5222D;">{0,}</font>
,比如<font style="color:#F5222D;">\^*b</font>
可以匹配<font style="color:#F5222D;">b</font>
,<font style="color:#F5222D;">^^^b</font>
等等 |
其中有些例子一定要注意!比如<font style="color:#F5222D;">ab{1,3}</font>
中重复的是<font style="color:#F5222D;">b</font>
而不是<font style="color:#F5222D;">ab</font>
,<font style="color:#F5222D;">(ab){1,3}</font>
这样重复的才是<font style="color:#F5222D;">ab</font>
。表达式<font style="color:#F5222D;">\^*b</font>
中重复的是<font style="color:#F5222D;">\^</font>
而不是<font style="color:#F5222D;">^</font>
,要从<font style="color:#F5222D;">左往右读</font>
正则表达式,转义符号有更高的优先级,需要和后面的字符整体认读
表达式<font style="color:#F5222D;">\d+\.?\d*</font>
在匹配<font style="color:#F5222D;">It costs $12.5</font>
时,匹配的结果是:成功;匹配到的内容是12.5;匹配到的位置开始于10,结束于14
表达式<font style="color:#F5222D;">go{2,8}gle</font>
在匹配<font style="color:#F5222D;">Ads by goooooogle</font>
时,匹配的结果是:成功;匹配到的内容是goooooogle;匹配到的位置开始于7,结束于17
- 位置匹配
表达式 | 匹配 |
---|---|
<font style="color:#F5222D;">^</font> |
在字符串开始的地方匹配,符号本身不匹配任何字符 |
<font style="color:#F5222D;">$</font> |
在字符串结束的地方匹配,符号本身不匹配任何字符 |
<font style="color:#F5222D;">\b</font> |
匹配一个单词边界,也就是单词和空格之间的位置,符号本身不匹配任何字符 |
<font style="color:#F5222D;">\B</font> |
匹配非单词边界,即左右两边都是<font style="color:#F5222D;">\w</font> 范围或者左右两边都不是<font style="color:#F5222D;">\w</font> 范围时的字符缝隙 |
<font style="color:#F5222D;">^aaa</font>
在匹配<font style="color:#F5222D;">xxx aaa xxx</font>
时,匹配结果是:失败。因为<font style="color:#F5222D;">^</font>
要求在字符串开始的地方匹配
表达式<font style="color:#F5222D;">aaa$</font>
在匹配<font style="color:#F5222D;">xxx aaa xxx</font>
时,匹配结果是:失败。因为<font style="color:#F5222D;">$</font>
要求在字符串结束的地方匹配
表达式<font style="color:#F5222D;">.\b.</font>
在匹配<font style="color:#F5222D;">@@@abc</font>
时,匹配结果是:成功;匹配到的内容是<font style="color:#F5222D;">@a</font>
;匹配到的位置开始于2,结束于4
表达式<font style="color:#F5222D;">\bend\b</font>
在匹配<font style="color:#F5222D;">weekend,endfor,end</font>
时,匹配结果是:成功;匹配到的内容是end;匹配到的位置开始于15,结束于18
三、re模块(三大搜索模块)
在Python中,通过内置的re模块提供对正则表达式的支持。正则表达式会被编译成一系列的字节码,然后由通过C编写的正则表达式引擎进行执行表达式 | 匹配 | 返回值 |
---|---|---|
<font style="color:#F5222D;">compile(pattern[, flags])</font> |
根据包含正则表达式的字符串创建模式对象 | re对象 |
<font style="color:#F5222D;">search(pattern, string[, flags])</font> |
在字符串中查找 | 第一个匹配到的对象或者Non |
<font style="color:#F5222D;">match(pattern, string[, flags])</font> |
在字符串的开始处匹配模式 | 在字符串开头匹配到的对象或者None |
<font style="color:#F5222D;">findall(pattern, string,flags)</font> |
列出字符串中模式的所有匹配项 | 所有匹配到的字符串列表 |
<font style="color:#F5222D;">compile(pattern[, flags])</font>
:
<font style="color:#F5222D;">compile()</font>
完成一次转换后,再次使用该匹配模式的时候就不用进行转换了。经过<font style="color:#F5222D;">compile()</font>
转换的正则表达式对象也能使用普通的re方法。其用法如下
经过
import re
pat = re.compile('abc123')
print(pat.match('abc1234'))
<re.Match object; span=(0, 6), match='abc123'>
print(pat.match('abc1234').group())
abc123
<font style="color:#F5222D;">compile()</font>
方法编译过后的返回值是个re对象,它可以调用<font style="color:#F5222D;">match()</font>
、<font style="color:#F5222D;">search()</font>
、<font style="color:#F5222D;">findall()</font>
等其他方法,但其他方法不能调用<font style="color:#F5222D;">compile()</font>
方法。实际上,<font style="color:#F5222D;">match()</font>
和<font style="color:#F5222D;">search()</font>
等方法在使用前,Python内部帮你进行了compile的步骤
那么是使用compile()还是直接使用<font style="color:#F5222D;">re.match()</font>
呢?看场景!如果你只是简单的匹配一下后就不用了,那么<font style="color:#F5222D;">re.match()</font>
这种简便的调用方式无疑来得更简单快捷。如果你有个模式需要进行大量次数的匹配,那么先<font style="color:#F5222D;">compile</font>
编译一下再匹配的方式,效率会高很多
以下都可直接通过re模块调用方法形式
<font style="color:#F5222D;">match(pattern,string[,flags]</font><font style="color:#F759AB;">)</font>
<font style="color:#F5222D;">match()</font>
方法会在给定字符串的<font style="color:#F5222D;">开头</font>
进行匹配,如果匹配不成功则返回<font style="color:#F5222D;">None</font>
,匹配成功返回一个匹配对象,这个对象有个<font style="color:#F5222D;">group()</font>
方法,可以将匹配到的字符串给出
对于一个
ret = re.match(r'cherry','dherry123')
print(ret)
None
ret = re.match(r'cherry','cherry123')
print(ret)
<re.Match object; span=(0, 6), match='cherry'>
obj = re.match(r'cherry','cherry123')
print(obj.group())
cherry
<font style="color:#F5222D;"><_sre.SRE_Match object; span=(0, 3), match='abc'></font>
对象,span指的是匹配到的字符在字符串中的位置下标,分别对应start和end。需要注意的是不包括end位置的下标,它是右开口的
<font style="color:#F5222D;">search(pattern,string[,flags]</font>)
<font style="color:#F5222D;">不用固定在文本的开头</font>
python
ret = re.search(r'ry1','cherry123')
print(ret)
<re.Match object; span=(4, 7), match='ry1'>
4. <font style="color:#F5222D;">findall(pattern,string[,flags]</font>)
作为re模块的三大搜索函数之一,<font style="color:#F5222D;">findall()</font>
和<font style="color:#F5222D;">match()</font>
、<font style="color:#F5222D;">search()</font>
的不同之处在于,前两者都是单值匹配,找到一个就忽略后面,直接返回不再查找了。而findall是全文查找,它的返回值是一个匹配到的字符串的列表。这个列表没有group()方法,没有start、end、span,更不是一个匹配对象,仅仅是个列表!如果一项都没有匹配到那么返回一个空列表
obj = re.findall(r'ry1','cherry123ry1334ry1444')
print(obj)
['ry1', 'ry1', 'ry1']