一,介绍
正则表达式(RE)是一种小型的,高度专业化的编程语言,在python中它内嵌在python中,并通过re模块实现。正则表达式模式被编译成一系列的字节码,然后由C编写的匹配引擎执行。
字符匹配(普通字符,元字符):
1 普通字符:大多数字符和字母都会和自身匹配
>>> re.findall('alex','yuanaleSxalexwupeiqi')
['alex']
2 元字符:. ^ $ * + ? { } [ ] | ( ) \
二,元字符
(一)点.通配符,代替除了换行符\n以外的任意一个字符
>>> import re >>> re.findall("alex","sdffalexjj") ['alex'] >>> re.findall("a..x","sdffalexjj") ['alex'] >>> re.findall("a...x","sdffalexjj") []
(二)尖角号^,表示以后面的字符串开头;$符,表示以前面的字符串结尾。
>>> re.findall("^a..x","asdffalexjj") [] >>> re.findall("^a..x","asdxfalexjj") ['asdx'] >>> re.findall("a..x$","asdxfa22x") ['a22x']
(三)重复符号,* + ? { }
1,*是重复紧挨着的字符,从0次到无穷次
>>> re.findall("alex*","asdxfale") ['ale']
2,+是1到无穷次,如果没有(0次)就匹配不上
>>> re.findall("alex+","asdxfale") [] >>> re.findall("alex+","asdxfalexxx") ['alexxx']
3,?是0或者1次
>>> re.findall("alex?","asdxfalexxx") ['alex'] >>> re.findall("alex?","asdxfale") ['ale']
4,{}自定义范围 {0,}==* {1,}==+ {0,1}==? {6}==重复6次 {1,6}重复1到6次
>>> re.findall("alex{6}","asdxfalexxxxxx") ['alexxxxxx'] >>> re.findall("alex{6}","asdxfalex") [] >>> re.findall("alex{0,1}","asdxfalex") ['alex'] >>> re.findall("alex{0,1}","asdxfale") ['ale']
注意*,+,?等都是贪婪匹配,后面加?号使其变成惰性匹配
>>> re.findall('abc*?','abcccccc') ['ab'] >>> re.findall('abc*','abcccccc') ['abcccccc'] >>> re.findall('abc+?','abcccccc') ['abc']
(四)字符集[]
实现或的逻辑
>>> re.findall('x[yz]','xyuuxzuu') ['xy', 'xz'] >>> re.findall('x[yz]p','xypuuxzuu') ['xyp'] >>> re.findall('x[y,z]p','xypuuxzuux,p') ['xyp', 'x,p']
[]内只有三个字符例外
1,-表示范围
>>> re.findall('x[a-z]','xypuuxzuux,p') ['xy', 'xz'] >>> re.findall('x[a-z]*','xypuuxzuux') ['xypuuxzuux'] >>> re.findall('x[a-z]*','xypuuxzuux9n') ['xypuuxzuux']
2,^非
>>> re.findall('x[^a-z]','x12') ['x1'] >>> re.findall('x[^a-z]','xy') [] >>> re.findall("\([^()]*\)","12+(34*6+2-5*(2-1))") ['(2-1)']
3,\ 后面跟元字符去除特殊功能,比如\.
后面跟普通字符实现特殊功能,比如\d
\d 匹配任何十进制数;它相当于类 [0-9]。
\D 匹配任何非数字字符;它相当于类 [^0-9]。
\s 匹配任何空白字符;它相当于类 [ \t\n\r\f\v]。
\S 匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。
\w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
\W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
\b 匹配一个特殊字符边界,比如空格 ,&,#等
>>> re.findall("\d","12+(34*6+2-5*(2-1))") ['1', '2', '3', '4', '6', '2', '5', '2', '1'] >>> re.findall("\d+","12+(34*6+2-5*(2-1))") ['12', '34', '6', '2', '5', '2', '1'] >>> re.findall("[0-9]+","12+(34*6+2-5*(2-1))") ['12', '34', '6', '2', '5', '2', '1'] >>> re.findall("\D+","12+(34*6+2-5*(2-1))") ['+(', '*', '+', '-', '*(', '-', '))'] >>> re.findall("\D+","hello world") ['hello world'] >>> re.findall("\s+","hello world") [' '] >>> re.findall("\S+","hello world") ['hello', 'world'] >>> re.findall("\w+","hello_world") ['hello_world'] >>> re.findall("\W+","~!@#$%^&*()") ['~!@#$%^&*()'] >>> re.findall("www\.baidu","www.baidu") ['www.baidu']
\b的用法讨论。re.findall("I\b","I am ooo"),这里面python解释器会识别出\b,并处理后交给re模块,re模块收到的不再是\b,于是产生问题。
解决方法1:使用r(raw string原生字符串)re.findall(r"I\b","I am ooo")
解决方法2:使用\\,由python解释器处理一次,去掉一个\,传给re模块就变成\b,re.findall("I\\b","I am ooo")
举例:找出"c\l",反推re模块接收为"c\\l",反推python解释器接收为"c\\\\l",最后re.findall("c\\\\l","I am oc\lo")
>>> re.findall("c\\\\l","I am oc\lo") ['c\\l']
(五)管道符|
|之前是一部分,|之后是一部分,两者是或的关系
>>> re.findall("ka|b","I am ka|b") ['ka', 'b']
(六)分组介绍
1,匿名分组使用()
>>> re.findall("(abc)+","I am abcd") ['abc']
注意:如果使用()分组,findall会优先显示匹配到的分组()里面的内容,而不是匹配的全部内容
如果就想要www.baidu.com完整匹配,需要在括号里加入?:
>>> re.findall("www\.(baidu|163)\.com","dfsgfwww.baidu.com112") ['baidu'] >>> re.findall("www\.(?:baidu|163)\.com","dfsgfwww.baidu.com112") ['www.baidu.com']
利用“优先显示匹配到的结果”解释下面的的现象
>>> re.findall("(abc)+","I am abcabcabc") ['abc']
上面实际把abc作为一个整体匹配,匹配到1次,结果是abcabcabc,但是只显示1个abc。如果想要全部显示,则需要使用上面的?:,如下:
>>> re.findall("(?:abc)+","I am abcabcabc") ['abcabcabc']
这种整体分组使用括号()匹配和单个字符匹配abc+是不一样的,如下abc+匹配到了3次而不是像上面分组的1次
>>> re.findall("abc+","I am abcabcabc") ['abc', 'abc', 'abc']
同理,分组的匹配出现多次的情况:
>>> re.findall("(abc)+","I am abcabc111abc") ['abc', 'abc']
2,命名分组:?P<name>对匹配没有任何影响,只是起了一个分组的名字叫name,而name作为group方法调用的参数。实际对匹配起作用的仍然是[a-z]+)\d+
>>> re.search("(?P<name>[a-z]+)\d+","alex36wusir34xialv33").group() 'alex36' >>> re.search("(?P<name>[a-z]+)\d+","alex36wusir34xialv33").group("name") 'alex' >>> re.search("(?P<name>[a-z]+)(?P<age>\d+)","alex36wusir34xialv33").group("age") '36'
三,方法
1,findall,返回所有满足匹配条件的结果,放在列表里
2,serach,在字符串内查找模式匹配,找到第一个然后返回一个对象。通过调用group()方法得到匹配的字符串,如果字符串没有匹配返回None
3,match,只会在开始处进行匹配
>>> re.match("(\d+)","alex36wusir34xialv33") >>> re.match("(\d+)","56alex36wusir34xialv33") <_sre.SRE_Match object; span=(0, 2), match='56'> >>> re.match("(\d+)","56alex36wusir34xialv33").group() '56'
4,split,分割函数
>>> re.split("[ |]","hello abc|def") ['hello', 'abc', 'def'] >>> re.split("[ab]","asdabcd") ['', 'sd', '', 'cd'] >>> re.split("[ab]","abc") ['', '', 'c']
5,sub,替换函数,4个参数:1:模式,2:替换为字符,3:搜索字符串,4:替换次数
>>> re.sub("\d+","A","J12abc234ffg55") 'JAabcAffgA' >>> re.sub("\d","A","J12abc234ffg55") 'JAAabcAAAffgAA' >>> re.sub("\d","A","J12abc234ffg55",4) 'JAAabcAA4ffg55' >>> re.subn("\d","A","J12abc234ffg55") ('JAAabcAAAffgAA', 7)
6,compile,模式先编译好,以后就可以直接调用。好处是写一次可以使用多次提高效率。
>>> com=re.compile("\d+") >>> com.findall("fjlkdad234hfjksd3421") ['234', '3421'] >>> com.findall("444adf555") ['444', '555']
7,finditer,返回的是迭代器对象,不再是列表。好处和迭代器是一样的。
>>> ret=re.finditer("\d","sdfds123fr") >>> next(ret).group() '1' >>> next(ret).group() '2'