@author: fighter

Python正则表达式知识点整理。

概述:在处理字符串时,经常会遇到查找符合某些复杂规则字符串的需求,正则表达式就是用于描述这些规则的工具。

首先,我们先掌握一下python中正则匹配需要用到的一些特殊字符。

1、行定位符:就是描述字符串的边界。"^“定义了字符串的开始位置,”$“定义了字符串的结束位置。
example: ^mo ,表示以 “mo” 为开头的字符串,可以匹配 “morning” 、“moabcd"等这些字符串,而不能匹配 类似"acdmo” 这样的字符串。
$mo 表示以"mo” 结尾的字符串,例如上述的 “acdmo”.

2、元字符:python预先定义好,用于统一代指某一类字符。
经常用到的包含以下七种:

① "." :匹配除换行符以外的任意字符。
     ![在这里插入图片描述]()例:可以匹配 "mr\nM\t" 中的 "m"、"r"、"M"、"\t"。
     ②"\w":匹配一个数字、字母、下划线或汉字。
     ③"\W":匹配除数字、字母、下划线或汉字以外的字符,与"\w"相反。
     ④"\s":匹配单个空白符(包括tab键和换行键)。
     ⑤"\S":除单个空白符以外的所有字符,与"\s"相反。
     ⑥"\d":匹配数字,例:可以与"ab3d"中的3匹配。
     ⑦"\b":匹配单词的开始或者结束,单词的边界通常是空格、标点符号和换行。
     例:"i like apple not banana","\ba" 与"apple"中的"a"匹配,
     “a\b"与"banana"中的"a"匹配。

3、限定符:匹配特定个数的指定字符,包含以下六种

①"?":匹配前面的字符0次或1次。例:"numbe?r" 可以匹配"numbr"和"number"。
②"+":匹配前面字符至少一次。例:"numbe+r" ,
表示"e"至少出现一次,可以匹配"number"、"numbeer"等。
③" * ":代表匹配前面字符0次或多次。
例:"numbe*r",表示"e"可以出现任意次,可以匹配"numbr"、"number" 或"numbeer"等。
④{n}:代表前面字符正好匹配n次。例:"numbe{2}r" 只能匹配"numbeer"。
⑤{n,}:代表前面字符至少匹配n次。例:"numbe{2,}r" 可以匹配"numbeer" 、"numbeeer"等
⑥{n,m}:代表前面字符至少匹配n次,至多匹配m次。
例:"numbe{2,3}r"可以匹配"numbeer"和"numbeeer"这两种形式。

4、字符类:除了元字符预先定义的匹配模式,用户需要根据需求定义某种匹配的范围,需要用"[]"将其包括。

例:我们想要匹配"a"、"d"、"m"、"h"任意一个字符的匹配方式,
可以写成"[admh]",表示匹配"admh"中四个字母的任意一个。
如果我们想要匹配所有小写字母,可以这样写:[a-z]`,所有数字的话:[0-9]

5、排除字符:根据需求,我们想要除了某些特定字符的任意一个字符,就要使用排除字符。方法就是将指定不要的字符用"[]“括起来,然后在最前面加上”^"。

例:[^abcd]:表示匹配除了"a"、"b"、"c"、"d" 以外的任意一个字符。

6、选择字符:提供多种匹配方式的模式,多个匹配方式之间用"|"隔开。

例如,我们想要匹配三个数字或者三个字母,可以这样写:"(\d{3})|([a-z]{3})"。

7、转义字符:"" 将有特殊意义的字符转换为普通字符.
例如"."代表任意字符,如果我们想要正常的"."字符,"127.0.0.1",就需要用到转义字符, 可以这样写匹配模式:"[1-9]{3}\.[0-9]\.[0-9]\.[1-9]"

了解完上述的基本内容,我们就正式开始介绍python中的正则匹配方法。
在Python里,提供了re模块,re模块中提供了一些方法用于实现正则表达式的操作。我们在进行正则匹配之前,需要首先导入re模块:import re
re模块里提供了以下三个方法进行正则匹配:
1、match()方法 :表示 从字符串的起始位置进行正则匹配,如果匹配成功,则返回一个对象,否则返回None.

语法格式:re.match(pattern,string,flags)
参数说明:
1、pattern:表示匹配模式
2、string:表示目标字符串,也就是要匹配的字符串。
3、flags:可选参数,用于控制匹配方式,常用的例如:re.I,表示无视字母大小写匹配。

import re
pattern = "[a-z]{3}"
string = "Abcde123acb"
match = re.match(pattern,string,re.I)
print(match)

打印结果:
<_sre.SRE_Match object; span=(0, 3), match='Abc'>
是一个对象!!!
这个对象有几个方法:
1、start():表示开始匹配的位置。
2、end():匹配的结束位置
3、span():返回一个以开始位置和结束位置组成的元组
4、string:表示目标字符串,注意后面没有小括号!!
5、group():表示匹配的结果

print(match.start())    #结果 0
print(match.end())    # 3
print(match.span())  #(0,3)
print(match.string)   # Abcde123acb
print(match.group()) #Abc

2、search()方法:与match()方法类似,唯一区别:search用于在整个字符串中搜索第一个符合匹配结果的对象。也就是说,search不仅仅在字符串的起始位置匹配,其他位置有符合的匹配也可以搜索,需要注意的是该方法搜索到第一个匹配成功的对象就不再搜索,直接返回结果。

import re
pattern = "[a-z]{3}"
string = "Abcde123acb"
match = re.search(pattern,string,re.I)
print(match.group()) 
打印结果:
Abc

3、findall()方法:用于在整个字符串中搜索所有符合正则表达式的字符串,并以列表形式返回。如果匹配成功,则返回包含所有匹配结果的列表,否则返回空列表。注意:该方法与前两个方法的返回结果不一样!!
语法格式:

findall(pattern,string,flags)
上述参数与match方法的一样。


import re
pattern = "[a-z]{3}"
string = "Abcde123acb"
match = re.findall(pattern,string,re.I)
print(match)

打印结果:
['Abc', 'acb']
注意:findall()方法返回一个普通的列表,不存在match和search返回
对象的start、end等五个方法,只需要使用列表操作就行。

拓展
一、compile()方法
我们都知道,python是解释型语言,每运行一次代码,都需要从上至下的进行解释运行,那么在实际项目中可能需要正则匹配多次,例如用户名、密码等,为了提升性能与代码运行速度,我们引入一个compile 模板。该模板原理是将需要多次匹配的pattern先进行解释,形成一个二进制文件,这样代码每次调用他进行正则匹配的时候就不用再解释一次。话不多说,直接写用法。

语法格式:
compile = re.compile(pattern,flags)
match = compile.match(目标字符串) |search(目标字符串)  | findall(目标字符串)
例:
import re
pattern = "[a-z]{3}"
string = "Abcde123acb"
compile = re.compile(pattern,re.I)
match = compile.findall(string)
print(match)
打印结果:
['Abc', 'acb']
总结:通过将正则匹配模式先生成二进制码文件,预先编号模板,
通过模板调用上述三个正则匹配的方法。

二、group()用法
表示分组的意思,对应着正则匹配pattern中的小括号,group()小括号里可以填写数字,表示选择pattern中第几个小括号匹配到的内容。
例:"(\d+)([a-z]+)(\d+)([a-z]+)",这个pattern中含有四个小括号,group(1)表示匹配(\d+)这个里面匹配到的东西。如果小括号里不写东西或者group(0)表示将匹配到的整个字符串打印。

import re
pattern = "(\d+)([a-z]+)(\d+)"
string = "Abcde123acb888acd"
compile = re.compile(pattern,re.I)
match = compile.search(string)
print(match.group())  # 打印结果:123acb888
print(match.group(0)) # 打印结果:123acb888
print(match.group(1)) # 打印结果:123
print(match.group(2)) # 打印结果:abc
print(match.group(3)) # 打印结果:888
注意:group()小括号内是从1 开始的。

Python的re模块中除了上述匹配方法外,还有以下两个比较常用的方法。
1、sub()方法:将目标字符串中符合正则匹配的字符替换成我们想要的字符,最终返回结果是一个新的字符串。

语法:sub(pattern,replace,string,count,flags)
参数说明:
   1、pattern:表示匹配模式
   2、replace:表示要替换成的字符串
   3、string:目标字符串
   4、count:可选参数,表示模式匹配后替换的最大次数,默认值为0,表示替换所有匹配。
   5、flags:可选参数,用于控制匹配方式,常用的例如:re.I,表示无视字母大小写匹配。
例:
import re
pattern = "\d+"
string = "Abcde123acb888acd"
#将字符串中的数字替换成”成功“两个字
newstr = re.sub(pattern,"成功",string)
print(newstr)
打印结果:
Abcde成功acb成功acd

增加替换次数:
import re
pattern = "\d+"
string = "Abcde123acb888acd"
newstr = re.sub(pattern,"成功",string,1)
print(newstr)
打印结果:
Abcde成功acb888acd

2、spilit()方法:将目标字符串按照正则匹配的字符串进行切割,最终返回结果是一个列表。

语法:re.split(pattern,string,maxSplit,flags)
参数说明:
1、pattern:正则匹配模式。
2、string:目标字符串。
3、maxSplit:可选参数,按照正则匹配字符串切割的最大切割次数,如果不写表示最大切割。
4、flags:可选参数,用于控制匹配方式,常用的例如:re.I,表示无视字母大小写匹配。
例:
import re
pattern = "\d+"
string = "Abcde123acb888acd"
newstr = re.split(pattern,string)
print(newstr)
打印结果:
['Abcde', 'acb', 'acd']

增加切割次数maxSplit
import re
pattern = "\d+"
string = "Abcde123acb888acd"
newstr = re.split(pattern,string,1)
print(newstr)
打印结果:
['Abcde', 'acb888acd']

正则里的贪婪匹配和非贪婪匹配

例:
import re
string ="mnaxca"
pattern="mn.*a"
贪婪匹配:像上例,匹配结果为"mnaxca",也就是最大限度的满足".*" 的任意多个字符。
非贪婪匹配:上例匹配结果是"mna",就是只要符合匹配就停止匹配,
因为".*"代表匹配0个或多个任意字符,那么最简单的就是0个字符咯,也就是匹配到"mna"

两者如何区分?我们看一下下边这个例子:

import re
string ="abcaxc"
pattern="ab.*c"
match = re.match(pattern,string)
print(match.group())
打印结果:
abcaxc
………………………………
import re
string ="abcaxc"
pattern="ab.*?c" #注意:此处的"*"号多了个“?”号
match = re.match(pattern,string)
print(match.group())
打印结果:
abc

总结:贪婪匹配是匹配最大限度的符合正则匹配模式的字符串;
非贪婪匹配是在限定符后面加上一个问号,匹配最小限度的符合正则匹配模式的字符串。