人生苦短,我用Python05:正则表达式
目录:
正则表达式
正则表达式在大多数语言中都存在,对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
不只是python有正则表达式,其他的语言也有,都是通过语言来调用正则表达式,而不是语言内置。
正则表达式分两种匹配方式,普通字符和元字符。
正则表达式使用方式
import re
re.findall(匹配规则,匹配字符串,标识符)
返回列表,将匹配到的字符
普通匹配字符串
>>> re.findall('why','wangwhy')
['why']
元字符
元字符 | 含义 |
---|---|
. |
匹配任意一个字符 |
^ |
代表开头 |
$ |
代表结尾 |
* |
代表零个或者多个前一个字符 |
+ |
代表一个或者多个前一个字符 |
? |
代表零个或者一个前一个字符 |
{} |
代表括号内数量的前一个字符 |
竖杠(怎么转义都不行,就是不显示) |
代表或的关系 |
[] |
括号内元素 |
() |
分组 |
\ |
转义,其后的元字符去除特殊功能,其后的普通字符实现特殊功能,引用对应自组所匹配的字符串 |
元字符实例
元字符'.'匹配
'.'可以匹配任意一个字符
>>> re.findall('w.y','wangwhy')
['why']
>>> re.findall('wh.','wangwhy')
['why']
如果改为'.*'代表匹配任意零到多个,不过正则匹配默认是贪婪的
>>> re.findall('w.*','wangwhy')
['wangwhy']
元字符'^'和'$'
匹配以why结尾的字符串
>>> re.findall('why$','wangwhy')
['why']
匹配以why开头的字符串
>>> re.findall('^why','wangwhy')
[]
匹配以wang开头的字符串
>>> re.findall('^wang','wangwhy')
['wang']
元字符*
,+
,?
和{}
>>> re.findall('why','wangwhyyyyyyyyyy')
['why']
>>> re.findall('why+','wangwhyyyyyyyyyy')
['whyyyyyyyyyy']
>>> re.findall('why?','wangwhyyyyyyyyyy')
['why']
>>> re.findall('why*','wangwhyyyyyyyyyy')
['whyyyyyyyyyy']
>>> re.findall('why{3}','wangwhyyyyyyyyyy')
['whyyy']
>>> re.findall('why{3,5}','wangwhyyyyyyyyyy')
['whyyyyy']
元字符|
>>> re.findall('why|wxy','wangwhywxywmy')
['why', 'wxy']
下面的方式是不行的
>>> re.findall('wh|xy','wangwhywxywmy')
['wh', 'xy']
元字符[]
首先在这里'.'不具备元字符的能力
>>> re.findall('w[.]y','wangwhy')
[]
>>> re.findall('w[.]y','wangw.y')
['w.y']
代表或的关系,下边为匹配h或x
>>> re.findall('w[hx]y','wangwhywxy')
['why', 'wxy']
代表a到z的所有字符,这个a到z是根据ascii码的顺序
>>> re.findall('[a-z]','why123')
['w', 'h', 'y']
代表0-9的所有字符
>>> re.findall('[0-9]','why123')
['1', '2', '3']
'^'在这里代表非的意思,就是除0到9之外的任意字符
>>> re.findall('[^0-9]','why123')
['w', 'h', 'y']
元字符\
'\'代表转移,把特殊的元字符变为正常的字符,把正常的字符富裕特殊的含义
特殊字符变为正常字符,我们要获取(why),在不转义的情况下
>>> re.findall('(why)','wang(why)')
['why']
转义后为
>>> re.findall('\(why\)','wang(why)')
['(why)']
正常字符富裕特殊含义,一下列举了常用的字符
- '\b'单词边界
- '\d'匹配数字字符
- '\D'匹配非数字字符
- '\s'匹配任何空白字符,等价于[ \t\n\r\f\v]
- '\S'匹配任何非空白字符
- '\w'匹配任何字母数字字符,等价于[a-zA-Z0-9_]
- '\W'匹配任何非字母数字字符,等价于[^a-zA-Z0-9_]
>>> re.findall('\d+','why123')
['123']
单词边界示例
>>> re.findall(r'\b\w+\b','why wanghongyu')
['why', 'wanghongyu']
这里我们在匹配的方式前面添加了r,这是为什么呢?下边是不加r的匹配到的
>>> re.findall('\b\w+\b','why wanghongyu')
[]
原因是python语言来调用正则表达式,但是由于'\b'在python中有别的含义,传递到正则表达式的参数不是正则表达式要的'\b',而是python语言中'\b'的含义——ascii码中的退格,所以没有匹配到,如果这时候我们把'\b'转义一下就可以了,即'\b',这样正则表达式接收到参数就为'\b'了。
>>> re.findall('\\b\w+\\b','why wanghongyu')
['why', 'wanghongyu']
ASCII码值(十进制)特殊字符的转义序列符
- \a 响铃(BEL) 007
- \b 退格(BS) 008
- \f 换页(FF) 012
- \n 换行(LF) 010
- \r 回车(CR) 013
- \t 水平制表(HT) 009
- \v 垂直制表(VT) 011
- \ 反斜杠 092
- ? 问号字符 063
- \' 单引号字符 039
- \" 双引号字符 034
- \0 空字符(NULL) 000
- \ddd 任意字符 三位八进制
- \xhh 任意字符 二位十六进制
不过我们在使用的时候直接加着r即可。
元字符'()'
元字符用于分组,匹配到的也是分组中的内容
>>> re.findall('y(\d+)','why123')
['123']
分组下边会在findall,search和match的区别中详细说
findall,search和match的区别
首先方法返回值
search和match会生成match对象
findall
>>> re.findall('y(\d+)','why123')
['123']
>>> re.findall('y(\d+)','why123y456')
['123', '456']
search
for python2
>>> re.search('y(\d+)','why123')
<_sre.SRE_Match object at 0x7fa4d89acf30>
for python3
>>> re.search('y(\d+)','why123')
<_sre.SRE_Match object; span=(2, 6), match='y123'>
可以看到search返回的是一个match对象
match
python2
>>> re.match('y(\d+)','why123')
>>> re.match('why(\d+)','why123')
<_sre.SRE_Match object at 0x7f34f78c1eb8>
python3
>>> re.match('y(\d+)','why123')
>>> re.match('why(\d+)','why123')
<_sre.SRE_Match object; span=(0, 6), match='why123'>
可以看到search返回的是一个match对象,但是与search不同的是,match只能在开头进行搜索
使用search和match的返回值
- group()返回被正则匹配的字符串,group可以有参数
- start()返回匹配的开始的位置
- end()返回匹配结束的位置
- span()返回一个元组,包含起始位置和结束位置
- groups()返回被正则匹配的所有字符串
- groupdict()返回被正则匹配的字典
group()
>>> re.search('([0-9]+)([a-z]+)([0-9]+)','123why456')
<_sre.SRE_Match object at 0x7f34f7945750>
>>> re.search('([0-9]+)([a-z]+)([0-9]+)','123why456').group()
'123why456'
>>> re.search('([0-9]+)([a-z]+)([0-9]+)','123why456').group(0)
'123why456'
>>> re.search('([0-9]+)([a-z]+)([0-9]+)','123why456').group(1)
'123'
>>> re.search('([0-9]+)([a-z]+)([0-9]+)','123why456').group(2)
'why'
>>> re.search('([0-9]+)([a-z]+)([0-9]+)','123why456').group(3)
'456'
groups()
>>> re.search('([0-9]+)([a-z]+)([0-9]+)','123why456').groups()
('123', 'why', '456')
groupdict()
>>> re.search('(?P<n1>[0-9]+)(?P<n2>[a-z]+)(?P<n3>[0-9]+)','123why456').groupdict()
{'n1': '123', 'n2': 'why', 'n3': '456'}
>>> re.search('(?P<n1>[0-9]+)(?P<n2>[a-z]+)([0-9]+)','123why456').groupdict()
{'n1': '123', 'n2': 'why'}
可以看到对只有指定了key的才能被groupdict()加入到字典中。
findall,search和match的分组
findall
>>> re.findall('(why)*','whywh123')
['why', '', '', '', '', '', '']
这里首先findall从开始的w进行匹配,然后匹配到why,直接添加到列表中,然后从y后开始匹配,对y后wh123的w进行匹配,没有匹配结果,返回一个''到字典中,然后是y,1,2,3,最后还有还会对空匹配,返回一个''。
>>> re.findall('(why)*','whywhy123')
['why', '', '', '', '']
这里会匹配到whywhy,但是由于分组的原因,()中为why,所以只显示括号内的why,但是,这个why是whywhy中后边的why,而不是前面的why,可以参考下边的例子
>>> re.findall('(\w){3}','why')
['y']
>>> re.findall('(\w)(\w)(\w)','why')
[('w', 'h', 'y')]
>>> re.findall('(\w)*','why')
['y', '']
不过对于*就会出现留空的问题
>>> re.findall('\d\w\d','1w2h3y4w5h6y')
['1w2', '3y4', '5h6']
>>> re.findall('(\d\w\d)','1w2h3y4w5h6y')
['1w2', '3y4', '5h6']
>>> re.findall('w\w+','why wxx wyy wzz')
['why', 'wxx', 'wyy', 'wzz']
>>> re.findall('(w\w+)','why wxx wyy wzz')
['why', 'wxx', 'wyy', 'wzz']
>>> re.findall('w(\w+)','why wxx wyy wzz')
['hy', 'xx', 'yy', 'zz']
>>> re.findall('w(\w+)y','why wxx wyy wzz')
['h', 'y']
可以看到()中的才会成为列表中的元素,但是如果有多个()列表中的元素就会转化成元组
>>> re.findall('(w)(\w+)','why wxx wyy wzz')
[('w', 'hy'), ('w', 'xx'), ('w', 'yy'), ('w', 'zz')]
如果()为嵌套的
>>> re.findall('((w)(\w+))','why wxx wyy wzz')
[('why', 'w', 'hy'), ('wxx', 'w', 'xx'), ('wyy', 'w', 'yy'), ('wzz', 'w', 'zz')]
search
>>> re.search('(why)*','whywh123')
<_sre.SRE_Match object at 0x7fa4d89b0030>
>>> re.search('(why)*','whywh123').group()
'why'
>>> re.search('(why)*','whywhy123').group()
'whywhy'
>>> re.search('w\w+','why wxx wyy wzz').group()
'why'
>>> re.search('w\w+','why wxx wyy wzz').groups()
()
>>> re.search('(w\w+)','why wxx wyy wzz').group()
'why'
>>> re.search('(w\w+)','why wxx wyy wzz').groups()
('why',)
>>> re.search('w(\w+)','why wxx wyy wzz').group()
'why'
>>> re.search('w(\w+)','why wxx wyy wzz').group(0)
'why'
>>> re.search('w(\w+)','why wxx wyy wzz').group(1)
'hy'
>>> re.search('w(\w+)','why wxx wyy wzz').groups()
('hy',)
>>> re.search('((w)(\w+))','why wxx wyy wzz').group()
'why'
>>> re.search('((w)(\w+))','why wxx wyy wzz').group(0)
'why'
>>> re.search('((w)(\w+))','why wxx wyy wzz').group(1)
'why'
>>> re.search('((w)(\w+))','why wxx wyy wzz').group(2)
'w'
>>> re.search('((w)(\w+))','why wxx wyy wzz').group(3)
'hy'
>>> re.search('((w)(\w+))','why wxx wyy wzz').groups()
('why', 'w', 'hy')
>>> re.search('(?P<n1>(?P<n2>w)(?P<n3>\w+))','why wxx wyy wzz').groupdict()
{'n1': 'why', 'n2': 'w', 'n3': 'hy'}
match
>>> re.match('(why)*','whywh123')
<_sre.SRE_Match object at 0x7fa4d89acf30>
>>> re.match('(why)*','whywh123').group()
'why'
>>> re.match('(why)*','whywhy123').group()
'whywhy'
>>> re.match('(123)*','whywh123')
<_sre.SRE_Match object at 0x7fa4d89acf30>
>>> re.match('(123)*','whywh123').group()
''
match和search的用法一直,只不过是从开通进行匹配,而match的group功能django的路由系统中。
正则表达式的贪婪匹配
python默认的正则表达式默认是以贪婪的匹配方式,可以加个?
>>> re.findall('y(\d+)','why123')
['123']
>>> re.findall('y(\d+?)','why123')
['1']
>>> re.findall('y(\d*)','why123')
['123']
>>> re.findall('y(\d*?)','why123')
['']
>>> re.findall('y(\d?)','why123')
['1']
>>> re.findall('y(\d??)','why123')
['']
特殊情况,如果前后有限制条件的时候这时贪婪模式并不适用
>>> re.findall('y(\d*?)w','why123why')
['123']
re模块的其他方法
compile()
re.compile(strPattern[,flag]) 这个方法是Pattern类的工厂方法,用于将字符串形式的正则表达式生成Pattern对象,第二个参数为Flag为匹配模式,取值可以是're.I | re.M'同时生效。
>>> p = re.compile(r'\d')
>>> print p.findall('123why456')
['1', '2', '3', '4', '5', '6']
sub()
用于字符串替换 re.sub(pattern,repl,string,max=0)
>>> re.sub("w.y","wanghongyu","why and wxy and wcy")
'wanghongyu and wanghongyu and wanghongyu'
>>> re.sub("w.y","wanghongyu","why and wxy and wcy",2)
'wanghongyu and wanghongyu and wcy'
>>> re.sub("w.y","wanghongyu","why and wxy and wcy",3)
'wanghongyu and wanghongyu and wanghongyu'
还有一个subn,可以返回替换了几次
>>> a,b = re.subn('\d','a','1w2h3y4w5h6y')
>>> print a
awahayawahay
>>> print b
6
>>> print re.subn('\d','a','1w2h3y4w5h6y')
('awahayawahay', 6)
在这里a, b = re.subn('\d','a','1w2h3y4w5h6y')等价于a = re.subn('\d','a','1w2h3y4w5h6y')[0]和b = re.subn('\d','a','1w2h3y4w5h6y')[1]
split()
正则匹配分割字符串
方法
def split(pattern, string, maxsplit=0, flags=0)
示例
>>> re.split("\d+","1why2why3why4why")
['', 'why', 'why', 'why', 'why']
可以通过指定maxsplit来指定最多分割几次
finditer()
finditer和findall匹配的方式是一样的,不同的是,finditer返回的是一个match对象的迭代器
>>> w = re.finditer('\d+','12 why44fdkjklfsa84jkklsajf12')
>>> for match in w:
... match.group(),match.span()
...
('12', (0, 2))
('44', (6, 8))
('84', (17, 19))
('12', (27, 29))
标志位
re.match(parttern,string,flags=0)
flags为编译的标志位,用于修改正则表达式的匹配方式,re.I使匹配不区分大小写,re.L做本地化识别(locale-aware)匹配,re.M多行匹配,影响$^不生效,re.S使.匹配包含换行符在内的所有字符
re.S
使.匹配包括换行在内的所有字符
>>> re.findall('.','why\nwhy')
['w', 'h', 'y', 'w', 'h', 'y']
>>> re.findall('.','why\nwhy',re.S)
['w', 'h', 'y', '\n', 'w', 'h', 'y']
re.U
根据Unicode字符集解析字符,受影响\w,\W,\b
re.X
该标志通过给予更灵活的格式
re.I
忽略大小写
re.M
多行匹配
>>> re.findall(r"^why\d+","why123\nwhy123")
['why123']
>>> re.findall(r"^why\d+","why123\nwhy123",re.M)
['why123', 'why123']
当然把^去掉也能匹配所有
>>> re.findall(r"why\d+","why123\nwhy123")
['why123', 'why123']
示例
匹配一个IP
>>> re.search(r'(([01]?\d?\d|2[0-4]\d|25[0-5])\.){3}([01]?\d?\d?|2[0-4]\d|25[0-5])','121.42.37.139')
<_sre.SRE_Match object; span=(0, 13), match='121.42.37.139'>
([01]?\d?\d|2[0-4]\d|25[0-5])这个括号是用来确认'|'的判定范围的,如果不加就会认为[01]?\d?\d,2[0-4]\d或25[0-5].为或的关系了
一些其他的方法
>>> re.findall('wang(hong|huang)yu','wanghongyu')
['hong']
>>> re.findall('wang(?:hong|huang)yu','wanghongyu')
['wanghongyu']