正则表达式就是字符串的匹配规则,在多数编程语言里都有相应的支持,python里对应的模块是 re。
re的匹配语法有以下几种
- re.match 从头开始匹配
- re.search 匹配包含
- re.findall 把所有匹配到的字符放到以列表中的元素返回
- re.split 以匹配到的字符当做列表分隔符
- re.sub 匹配字符并替换
- re.fullmatch 全部匹配
常用的表达式规则 红色加粗的为重要的常用的
- '.' 默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
>>> re.search('.','qasd') #字母可以匹配 <re.Match object; span=(0, 1), match='q'> >>> re.search('.','1asd') #数字可以匹配 <re.Match object; span=(0, 1), match='1'> >>> re.search('.','*asd') #特殊字符可以匹配 <re.Match object; span=(0, 1), match='*'> >>> re.search('..','*asd') #想匹配几个字符,就加几个点 <re.Match object; span=(0, 2), match='*a'>
- '^' 匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
>>> re.search('^','qasd') <re.Match object; span=(0, 0), match=''> >>> re.search('^a','qasd') >>> re.search('^a','abd') <re.Match object; span=(0, 1), match='a'> >>> re.search('^ab','abd') <re.Match object; span=(0, 2), match='ab'> >>> re.search('^b','abd') #没匹配到,无返回,相当于 re.match('b','abd')
- '$' 匹配字符结尾, 若指定flags MULTILINE ,re.search('foo.$','foo1\nfoo2\n',re.MULTILINE).group() 会匹配到foo1
#匹配以什么结尾 >>> re.search('b$','abd') >>> re.search('b$','ab') <re.Match object; span=(1, 2), match='b'> >>> re.search('b$','bab') <re.Match object; span=(2, 3), match='b'> #匹配格式 >>> re.match('b$','ab') >>> re.match('b$','b') <re.Match object; span=(0, 1), match='b'> >>> re.match('b$','bob') >>> re.match('b.b$','bob') <re.Match object; span=(0, 3), match='bob'>
- '*' 匹配字符开头,匹配*号前的字符0次或多次, re.search('a*','aaaabac') 结果'aaaa'
>>> re.search('a*','Alex') #匹配不到时,返回值为空 <re.Match object; span=(0, 0), match=''> >>> re.search('a*','Alex').group() '' >>> re.search('a*','alex').group() 'a' >>> re.search('a*','aaaalex').group() 'aaaa' >>> re.search('ab*','abaaex').group() #可以加两个字符,但事实上匹配的还是前一个字符 'ab' >>> re.search('ab*','ababbaex').group() 'ab' >>> re.search('ab*','abbbbaex').group() 'abbbb'
- '+' 匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']
>>> re.search('a+','sdf') >>> re.search('a+','abbaalex') <re.Match object; span=(0, 1), match='a'> >>> re.search('a+','aaab') <re.Match object; span=(0, 3), match='aaa'> >>> re.search('.+','aaab') #'.' 是匹配除\n外任意字符,在这里就是全部匹配 <re.Match object; span=(0, 4), match='aaab'> >>> re.search('ab+','aaab') #匹配 '+' 前的字符和最后一个字符 <re.Match object; span=(2, 4), match='ab'> >>> re.search('ab+','aaabab') <re.Match object; span=(2, 4), match='ab'> >>> re.search('ab+','aaabbbbab') <re.Match object; span=(2, 7), match='abbbb'> >>> re.search('ab+','bbbbb') #匹配不到
- '?' 匹配前一个字符1次或0次 ,re.search('b?','alex').group() 匹配b 0次
>>> re.search('a?','aaab') <re.Match object; span=(0, 1), match='a'> >>> re.search('a?','bbb') <re.Match object; span=(0, 0), match=''>
- '{m}' 匹配前一个字符m次 ,re.search('b{3}','alexbbbs').group() 匹配到'bbb'
>>> re.search('a{2}','ddd') >>> re.search('a{2}','addd') >>> re.search('a{2}','aaddd') #必须一次匹配两个 <re.Match object; span=(0, 2), match='aa'> >>> re.search('a{2}','adaadd') #全局匹配 <re.Match object; span=(2, 4), match='aa'> >>> re.search('a{2}','adaadd') <re.Match object; span=(2, 4), match='aa'> >>> re.search('.{2}','adaaadd') #'.' 是开头匹配两个 <re.Match object; span=(0, 2), match='ad'> >>> re.search('[0-9]{2}','1234adaaadd') #匹配两个数字 <re.Match object; span=(0, 2), match='12'>
- '{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']
>>> re.search('[a-z]','alex') <re.Match object; span=(0, 1), match='a'> >>> re.search('[a-z]{1,2}','alex') #尽可能匹配到最大 <re.Match object; span=(0, 2), match='al'> >>> re.search('[a-z]{1,2}','a2lex') <re.Match object; span=(0, 1), match='a'>
- '|' 匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'
>>> re.search('alex|Alex','alex') #匹配 alex 或 Alex <re.Match object; span=(0, 4), match='alex'> >>> re.search('a|Alex','alex') #匹配 a 或 Alex <re.Match object; span=(0, 1), match='a'> >>> re.search('[a|A]lex','alex') #匹配 alex 或 Alex <re.Match object; span=(0, 4), match='alex'>
- '(...)' 分组匹配, re.search("(abc){2}a(123|45)", "abcabca456c").group() 结果为'abcabca45'
>>> re.search('[a-z]+','alex123') <re.Match object; span=(0, 4), match='alex'> >>> re.search('([a-z]+)([0-9]+)','alex123') #分别匹配小写字母和数字 <re.Match object; span=(0, 7), match='alex123'> >>> re.search('([a-z]+)([0-9]+)','alex123').group() 'alex123' >>> re.search('([a-z]+)([0-9]+)','alex123').groups() #将分别匹配出的结果分开 ('alex', '123')
- '\A' 只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的,相当于re.match('abc',"alexabc") 或^
>>> re.search('\Aalex','alex789') #相当于 re.search('^alex','alex789')、re.match('alex','alex789') <re.Match object; span=(0, 4), match='alex'>
- '\Z' 匹配字符结尾,同$
>>> re.search('[0-9]\Z','al***ex789peiqi562233') #用法同 $ <re.Match object; span=(20, 21), match='3'>
- '\d' 匹配数字0-9
>>> re.search('\d','alex789') <re.Match object; span=(4, 5), match='7'> >>> re.search('\d+','alex789') <re.Match object; span=(4, 7), match='789'> >>> re.search('\d+','alex789peiqi562233') <re.Match object; span=(4, 7), match='789'>
- '\D' 匹配非数字
>>> re.search('\D+','alex789peiqi562233') <re.Match object; span=(0, 4), match='alex'> >>> re.search('\D+','al***ex789peiqi562233') <re.Match object; span=(0, 7), match='al***ex'>
- '\w' 匹配[A-Za-z0-9] ,即匹配除特殊字符之外的所有
>>> re.search('\w','al***ex789peiqi562233') <re.Match object; span=(0, 1), match='a'> >>> re.search('\w','alex789peiqi562233') <re.Match object; span=(0, 1), match='a'> >>> re.search('\w+','al***ex789peiqi562233') <re.Match object; span=(0, 2), match='al'> >>> re.search('\w+','alex789peiqi562233') <re.Match object; span=(0, 18), match='alex789peiqi562233'>
- '\W' 匹配非[A-Za-z0-9],即匹配特殊字符
>>> re.search('\W','al***ex789peiqi562233') <re.Match object; span=(2, 3), match='*'> >>> re.search('\W+','al***ex789peiqi562233') <re.Match object; span=(2, 5), match='***'>
- '\s' 匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 结果 '\t'
>>> s = 'alex\njack' >>> re.search('\s',s) <re.Match object; span=(4, 5), match='\n'> >>> re.search('\s','alex\njack\tdd\rmack') <re.Match object; span=(4, 5), match='\n'> >>> re.findall('\s','alex\njack\tdd\rmack') ['\n', '\t', '\r']
- '(?P<name>...)' 分组匹配 re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict("city") 结果{'province': '3714', 'city': '81', 'birthday': '1993'}
>>> s = '1307042000005250613' >>> re.search('(?P<province>\d{3})(?P<city>\d{3})(?P<bron_year>\d{4})',s) #不分组输出 <re.Match object; span=(0, 10), match='1307042000'> >>> re.search('(?P<province>\d{3})(?P<city>\d{3})(?P<bron_year>\d{4})',s).groups() #涉及分组,就用 groups() ('130', '704', '2000') >>> res = re.search('(?P<province>\d{3})(?P<city>\d{3})(?P<bron_year>\d{4})',s) >>> res.groupdict() #以字典形式输出 {'province': '130', 'city': '704', 'bron_year': '2000'}
re匹配语法详解
- re.match 匹配开头,从头开始,只匹配一个字符,匹配到就返回结果,匹配不到无返回
>>> re.match('[0-9]','abc1d3e')
-
re.search(pattern, string, flags=0)
根据模型去字符串中匹配指定内容,匹配单个
>>> re.search('[0-9]','abc1d3e') #从头开始匹配,全局匹配,匹配到一个就返回 <re.Match object; span=(3, 4), match='1'>
-
re.findall(pattern, string, flags=0)
match and search均用于匹配单值,即:只能匹配字符串中的一个,如果想要匹配到字符串中所有符合条件的元素,则需要使用 findall。
>>> re.findall('[0-9]','abc1d3e') #全局匹配,将所有匹配到的放入列表中返回 ['1', '3'] >>> if match_res: ... match_res.group() #有返回值的时候,返回结果,没有返回值,会报错 ... '1'
-
re.sub(pattern, repl, string, count=0, flags=0)
用于替换匹配的字符串,相比于str.replace功能更加强大
>>> re.sub('\d+','_','alex22jack23rain31jinxin50|mack-oldboy') #全部替换 'alex_jack_rain_jinxin_|mack-oldboy' >>> re.sub('\d+','_','alex22jack23rain31jinxin50|mack-oldboy',count = 2) #只替换前两个 'alex_jack_rain31jinxin50|mack-oldboy'
- re.split(pattern, string, maxsplit=0, flags=0)
>>> re.split('\d','alex22jack23rain31jinxin50') #只取一个数字,所以有空返回值 ['alex', '', 'jack', '', 'rain', '', 'jinxin', '', ''] >>> re.split('\d+','alex22jack23rain31jinxin50') #去所有的数字,因为最后一个数字后面没东西了,所以有一个空返回值 ['alex', 'jack', 'rain', 'jinxin', ''] >>> re.split('\d+|#|-','alex22jack23rain31jinxin50#mack-oldboy') #以数字、# 、- 分隔 ['alex', 'jack', 'rain', 'jinxin', '', 'mack', 'oldboy'] >>> re.split('\|','jinxin50|mack-oldboy') #'\' 是转译字符,为了以 '|' 分隔 ['jinxin50', 'mack-oldboy'] >>> re.split('\\\\','xin50\\mack-oldboy') #想以 '\' 分隔,必须是四个 '\' ['xin50', 'mack-oldboy'] >>> re.split('\\\\','xin50\mack-oldboy') ['xin50', 'mack-oldboy'] >>>s='9-2*5/3+7/3*99/4*2998+10*568/14' >>>re.split('[\*\-\/\+]',s) ['9', '2', '5', '3', '7', '3', '99', '4', '2998', '10', '568', '14'] >>> re.split('[\*\-\/\+]',s,3) #只分隔前三个 ['9', '2', '5', '3+7/3*99/4*2998+10*568/14']
-
re.fullmatch(pattern, string, flags=0)
整个字符串匹配成功就返回re object, 否则返回None
>>> re.fullmatch('alex','alex123') #必须完全匹配 >>> re.fullmatch('alex123','alex123') <re.Match object; span=(0, 7), match='alex123'> >>> re.fullmatch('\w+@\w+\.(com|cn|edu)',"alex@oldboyedu.cn") <re.Match object; span=(0, 17), match='alex@oldboyedu.cn'>
- re.compile() 与直接使用 fullmatch 相比,可提高效率。
>>> pattern = re.compile('\w+@\w+\.(com|cn|edu)') >>> pattern.fullmatch('alex@oldboyedu.cn') <re.Match object; span=(0, 17), match='alex@oldboyedu.cn'>
Flags标识符
- re.I(re.IGNORECASE):忽略大小写(括号内是完整写法,下同)
- M(MULTILINE):多行模式,改变 '^' 和 '$' 的行为
- S(DOTALL):改变 '.' 的行为,make the '.' special character match any character at all, including a newline; without this flag, '.' will match any except a newline.
- X(re.VERBOSE):可以给你的表达式写注释,使其可读,下面这两个意思一样。
>>> re.search('a','Alex',re.I) #忽略大小写 <re.Match object; span=(0, 1), match='A'> >>> re.search('foo.$','foo1\nfoo2\n') <re.Match object; span=(5, 9), match='foo2'> >>> re.search('foo.$','foo1\nfoo2\n',re.M) #匹配一行的结尾 <re.Match object; span=(0, 4), match='foo1'> >>> re.search('.','\n') #匹配换行符之外的所有字符 >>> re.search('.','\n',re.S) #匹配所有的字符 <re.Match object; span=(0, 1), match='\n'> >>> re.search('. #test','alex\n') >>> re.search('. #test','alex\n',re.X) #加进注释 <re.Match object; span=(0, 1), match='a'>