Regular Expression
在上一节中提到了Python可以利用字符串的find和index方法来查找字符串,但是这种方法只能查找固定的字符串,也就是精确查找.而我们在正常使用过程中模糊查找其实更为常见,例如查找所有以a开头,以b结尾的字符串,这就需要利用正则表达式来实现搜索.
正则表达式的基本语法如下:
| 符号 | 含义 | 示例 |
|---|---|---|
| . | 匹配除换行符外的任意单个字符 | a.b匹配开头为a,结尾为b的连续三个字符 |
| \^ | 匹配字符串的开头 | ^abc匹配以abc开头的字符串 |
| \$ | 匹配字符串的结尾 | $abc匹配以abc结尾的字符串 |
| [] | 定义字符集合,匹配其中任意一个字符 | [aeiou]匹配任意一个原因字母 |
| [^] | 定义字符集合,匹配不在其中任意的一个字符 | [^0-9]匹配任意非数字字符 |
| - | 字符类中表示范围 | [a-z]匹配任意小写字母 |
| \* | 匹配前面的子表达式零次或多次 | a*e匹配开头有且仅有0个或多个a,结尾为e的字符 |
| + | 匹配前面的子表达式一次或多次 | a+e匹配开头有且仅有1个或多个a,结尾为e的字符 |
| ? | 匹配前面的子表达式零次或者一次 | colou?r匹配color和colour |
| {n} | 精确匹配前面的子表达式n次 | da{3}e匹配daaae |
| {n,} | 至少匹配前面的子表达式n次 | da{2,}e匹配daae,daaae等 |
| {n,m} | 匹配前面的子表达式n次到m次 | a{2,4}匹配aa,aaa,aaaa |
| () | 定义子表达式或捕获组 | (ab)+匹配ab,abab等 |
正则表达式里的特殊字符如果需要作为普通字符使用,则需要在其前面加上反斜杠\进行转义,如:
| 符号 | 含义 | 等价符号 |
|---|---|---|
| \d | 匹配任意数字 | 等价于[0-9] |
| \D | 匹配任意非数字 | 等价于[^0-9] |
| \w | 匹配任意单词字符(字母,数字,下划线) | [a-zA-Z0-9_] |
| \W | 匹配任意非单词字符(字母,数字,下划线) | [^a-zA-Z0-9_] |
| \s | 匹配任意空白字符(空格,制表符,换行符) | [ \t\n] |
| \S | 匹配任意非空白字符(空格,制表符,换行符) | [^ \t \n] |
| \b | 边界匹配符,如果在左边出现要求是开头,右边则是结尾,同时出现则精确匹配 | ^,$,"" |
这里我们对前面提到的正则表达式的基本语法进行一些补充说明:
*,+,?和{n,m}这些量词都是贪婪的也就是他会尽可能多的匹配字符,如下:
1
2
3import re
text="<div>abc</div><div>def</div>"
re.findall(r"<div>.*</div>",text) # ['<div>abc</div><div>def</div>']这里的.*会尽可能多的匹配字符,直到最后一个</div>为止.如果想让其变为非贪婪模式,则可以在量词后面加上?,如下:
1
2
3# 非贪婪模式
re.findall(r"<div>.*?</div>", text)
# 结果: ['<div>abc</div>', '<div>def</div>']匹配开头或者结尾的时候只写了部分模式,这并不会匹配整个字符串,而是匹配字符串的开头或者结尾部分,如下:
1
2re.findall(r"^abc", "abcdef") # ['abc']
re.findall(r"def$", "abcdef") # ['def']忘记了对特殊字符做转义
1
re.findall(r"d{3}.txt","dddktxt") # ['dddktxt']
字符集和字符分组混用错误:[abc]可以匹配单个字符’a’,’b’和’c’;而(abc)匹配整个字符串”abc”.
re模块是Python标准库中用于正则表达式操作的模块,提供查找,匹配,替换,分组等功能.re模块的基本函数为
| 函数 | 作用 |
|---|---|
| re.match(pattern,string) | 从字符串开头匹配 |
| re.search(pattern,string) | 搜索整个字符串,找到第一个匹配 |
| re.findall(pattern,string) | 返回所有匹配的字符串列表 |
| re.finditer(pattern,string) | 返回迭代器,每个元素是Match对象 |
| re.fullmatch(pattern,string) | 整个字符串必须完全匹配 |
| re.split(pattern,string) | 按模式分割字符串 |
| re.sub(pattern,repl,string) | 替换匹配的部分 |
| re.subn(pattern,repl,string) | 返回(替换后字符串,替换次数) |
返回的match对象的常用属性:
1 | import re |
re模块提供了一个编译模式,可以提高后续使用相同的正则表达式的运行效率.re.compile的作用会将一个正则表达式编译成一个正则对象,后续可以重复使用这个对象来匹配字符串.这样的好处是
- 复用性强,不需要每次都写pattern,直接使用正则对象的方法.
- 效率更高,编译过的正则对象会缓存,特别是同一个模式需要多次匹配时,具有更高的性能
其基本语法为:
1 | import re |
上面提到了re.compile的标准语法中存在一个flags变量,实际上re的每个函数都有这个变量,在此介绍flags变量的值及其作用:
| FLAGS | 作用 |
|---|---|
| re.I(re.IGNORECASE) | 忽略大小写,匹配时不区分大小写 |
| re.M(re.MULTILINE) | 让^和$作用于每一行的开头和结尾,默认仅匹配整个字符串的开头结尾 |
| re.S(re.DOTALL) | 默认.不匹配换行,开启后可以匹配换行 |
| re.X(re.VERBOSE) | 正则里可以加空格和注释,提高可读性 |