day40:正则表达式

正则表达式(regex)

定义:使用字符和特殊符号组成的能够描述某一类字符串的表达式。

动机:

1.文本处理称为计算机的常见工作

2.文本处理中,根据内容筛选、查找、匹配指定的内容又是常用功能之一

3.方便快速的解决上述问题,正则表达式应运而生

特点和具体使用:

*是一种高级的文本搜素匹配模式,提供了丰富的功能

*正则表达式支持多种语言,使用方便

*MongoDB可以存储正则表达式

*在爬虫中大量使用正则表达式进行html文本的匹配

*Django,Tornado等框架中,路由的匹配

正则表达式规则及元字符

元字符:正则表达式中定义的,具有特定意义的符号

import re

re模块是python的标准库模块,是用来处理正则表达式的

re.findall(regex,string)

功能:使用regex去匹配string中的内容,如果匹配到则以一个列表的方式进行返回

*普通字符:

元字符:abc

匹配规则:匹配字符串的内容

示例:

In [6]: re.findall('abc123','abc123deabc123fgh')

Out[6]: ['abc123', 'abc123']

In [7]: re.findall('abc\.','abc.123deabc.123fgh')

Out[7]: ['abc.', 'abc.']

*或连接多个正则表达式

元字符:|

匹配规则:abc|def 表示既能匹配abc也能匹配def

示例:

In [8]: re.findall('abc|def','abcdksdefdfs')

Out[8]: ['abc', 'def']

In [9]: re.findall('abc|def|dfs','abcdksdefdfs')

Out[9]: ['abc', 'def', 'dfs']

In [11]: re.findall('abc|bcd','abcde’)#不能查找重叠

Out[11]: ['abc']

In [16]: re.findall('ab|cd','cdeabc')

Out[16]: ['cd', 'ab']

*竖线左右不要加空格,除非是要匹配空格

*不能查找重叠

*匹配任意一个字符

元字符:‘.’

匹配规则:使用“.”代表任意一个字符,不能代表‘\n’

例:f.o -> foo\fao\f@o\f5\…

In [12]: re.findall('f.o','from china')

Out[12]: ['fro']

In [13]: re.findall('f.o.','from china')

Out[13]: ['from']

*匹配字符串开头

元字符:^

匹配规则:匹配字符串的开头位置内容

例:^abc -> 以abc开头的字符串

In [17]: re.findall('^From','From China')

Out[17]: ['From']

In [18]: re.findall('^from','I come from China')

Out[18]: []

*匹配字符串结尾

元字符:$

匹配规则:当一个正则表达式是一个字符串结尾时能匹配出来

例:\.py$ -> test.py\find.py

In [21]: re.findall('py$','test.py find.py')

Out[21]: ['py']

In [22]: re.findall('py$','python')

Out[22]: []

In [23]: re.findall('.....py$','test.py find.py')

Out[23]: ['find.py']

*匹配0次或多次正则表达式

元字符:‘*’

匹配规则:用 * 匹配他前面出现的正则表达式0次或多次

例:

ab* -> a\ab\abbb\abbbbb

a.* -> a\ab\ac\asgsfdg 都可以匹配到

In [24]: re.findall('ab*','abcde')

Out[24]: ['ab']

In [25]: re.findall('a.*','abcde') #.出现0次或多次

Out[25]: ['abcde']

In [26]: re.findall('ab*','abbbbbcde')

Out[26]: ['abbbbb']

In [27]: re.findall('ab*','abababab')

Out[27]: ['ab', 'ab', 'ab', 'ab']

*字符后面的*号代表多个前面的字符

*匹配前面的正则表达式一次或多次

元字符:‘+’

匹配规则:匹配前面出现的正则表达式至少出现一次

示例:

In [28]: re.findall('ab+','abbb')

Out[28]: ['abbb']

In [29]: re.findall('ab+','accbb')

Out[29]: []

*匹配前面出现的正则表达式0次或一次

元字符:’?’

匹配规则:匹配前面的正则表达式,0次,1次

示例:

In [32]: re.findall('ab?','abadf')

Out[32]: ['ab', 'a']

In [33]: re.findall('ab?','abbbb')

Out[33]: ['ab']

In [36]: re.findall('a?','abcbbb')

Out[36]: ['a', '', '', '', '', '', '']

*匹配前面的正则表达式指定的次数

元字符: N表示一个正整数

匹配规则:匹配前面的正则表达式出现N次

示例:

In [37]: re.findall('a.','absdfsaa')

Out[37]: ['absd']

In [38]: re.findall('ab','abbbbbb')

Out[38]: ['abbbb']

*匹配前面出现的正则表达式指定次数区间

元字符:

匹配规则:匹配前面的正则表达式m-n次

示例:

In [41]: re.findall('ab','abbbcdbbbefgh')

Out[41]: ['abbb'] #匹配最少3个,最多6个

In [42]: re.findall('ab','abbbbbcdbbbefgh')

Out[42]: ['abbbbb']

In [43]: re.findall('.','abcdefghi')

Out[43]: ['abcdefgh']

In [46]: re.findall('^.','abcde’)#以任意的6-8位字符开头(可用作密码)

Out[46]: []

*匹配字符集合

元字符:[abcdef] #里面可以传入任意字符,可以传入字符区间[a-z]、[A-Z]、[0-9]、[a-zA-Z0-9]

匹配规则:匹配集合中任意一个字符

例:

[abcd] -> a b c d

[a-zA-Z] -> 匹配所有字母 a A 。。。

[abc0-9] -> 匹配a b c 0 1 2 3 4 5 6 7 8 9

In [47]: re.findall('[0-9][abcd][A-Z]','1bDdg3cK')

Out[47]: ['1bD', '3cK']

In [48]: re.findall('^[0-9a-zA-Z]$’,’asbd123kw')

Out[48]: []

In [118]: re.findall('^[0-9a-zA-Z]$','asb123kw')

Out[118]: ['asb123kw']

*字符集合取非

元字符 [^…]

匹配规则:匹配任意一个非集合中的字符

例:

[^abcd] -> 可以匹配除了a b c d中的任意字符

[^_a-zA-Z0-9] -> 匹配任意一个特殊字符 $ ^ % * ( &

In [51]: re.findall('[^aeiou]','hello world')

Out[51]: ['h', 'l', 'l', ' ', 'w', 'r', 'l', 'd']

In [52]: re.findall('[^0-9]','hello 12306')

Out[52]: ['h', 'e', 'l', 'l', 'o', ' ']

*任意数字/非数字 字符

元字符:\d \D

匹配规则:

\d匹配任意一个数字字符 [0-9]

\D匹配任意一个非数字字符 [^0-9]

例:

\d -> 任意一个三位数

\D -> a % d $ * …(只要不是数字就行)

In [53]: re.findall('\d','hello 12306')

Out[53]: ['1', '2', '3', '0', '6']

In [54]: re.findall('\d','hello 12306')

Out[54]: ['123']

In [55]: re.findall('\d','hello 123068')

Out[55]: ['123', '068']

In [56]: re.findall('\D','hello 123068')

Out[56]: ['h', 'e', 'l', 'l', 'o', ' ']

In [57]: re.findall('\D','hello 123068')

Out[57]: ['hel', 'lo ']

*匹配任意 数字字母下划线 或 非数字字母下划线

元字符:\w \W

匹配规则:

\w匹配任意数字字母下划线 [_a-zA-Z0-9]

\W匹配任意非数字字母下划线 [^_a-zA-Z0-9]

示例:

In [3]: re.findall('\w','hello')

Out[3]: ['h', 'e', 'l', 'l', 'o']

In [60]: re.findall('[A-Z]\w*','Hello World')

Out[60]: ['Hello', 'World']

In [62]: re.findall('\w*-\d+','xiaoming-64')

Out[62]: ['xiaoming-64']

In [63]: re.findall('\W','xiaoming-64')

Out[63]: ['-']

In [65]: re.findall('\w*','re_test.py')

Out[65]: ['re_test', '', 'py', '']

*匹配 空白字符 / 非空白字符

元字符:\s \S

匹配规则:空白字符: ‘ ’、\n 、\r 、\0(字符串的结束标识) 、\t

\s匹配其中任意一个空白字符

\S匹配任意一个非空白字符

示例:

In [67]: re.findall('hello\s[a-zA-Z]*','hello China')

Out[67]: ['hello China']

In [68]: re.findall('hello\s[a-zA-Z]*','helloChina')

Out[68]: []

In [69]: re.findall('hello\s+China','hello China')

Out[69]: ['hello China']

In [70]: re.findall('\S*','hello China')

Out[70]: ['hello', '', 'China', ''] #空在讲函数的时候再议

*匹配字符串的开头和结尾(不常用)

元字符:\A \Z

匹配规则:

\A匹配字符串开头 ^

\Z匹配字符串结尾 $

示例:

In [71]: re.findall('\Ahello','hello China')

Out[71]: ['hello']

In [72]: re.findall('\Ahello','aa hello China')

Out[72]: []

In [74]: re.findall('China\Z','hello China')

Out[74]: ['China']

In [76]: re.findall('\Ahello\Z','hello') #绝对匹配

Out[76]: ['hello']

In [77]: re.findall('\Ahello\Z','hello China')

Out[77]: []

*匹配单词边界/非单词边界

元字符:\b \B (不代表任何字符,只是一个边界)

匹配规则:将连续字母认为是一个单词,而字母与非字母的交界认为是单词边界

示例:

In [79]: re.findall(r'\bBeijing\b','Welcome to Beijing')

Out[79]: ['Beijing']

In [80]: re.findall(r'\bjing\b','Welcome to Beijing')

Out[80]: []

In [82]: re.findall(r'jing\b','Welcome to Beijing')

Out[82]: ['jing']

In [85]: re.findall(r'\bto\b','Welcome to Beijing')

Out[85]: ['to']

In [86]: re.findall(r'\bto\b','Welcome to tornado')

Out[86]: ['to'] #只匹配出第一个

In [88]: re.findall(r'\bto\b','Welcome to to_rnado')

Out[88]: ['to']

*数字和下划线被认为可以是单词中的部分

总结:

字符:匹配实际字符

匹配单个字符:. [] \w \W \d \D \s \S

匹配正则表达式重复次数:* + ? {}

匹配位置(开头、结尾或边界):^ $ \A \Z \b \B

其他:| [^…]

raw(原始字符串格式)字符串特点:不会进行转义,将字符串内所有的内容原样使用

In [90]: re.findall('\\\\n','hello \\n')

Out[90]: ['\\n']

In [91]: re.findall(r'\\n','hello \\n')

Out[91]: ['\\n']

只要带\的前面都带上r

正则表达式转义

当正则表达式中要匹配 \ * . ? {} [] () ‘’ “” 这些字符时,需要使用’\’进行转义。此时如果为了避免字符串解析为正则表达式带来的麻烦,最好使用raw字符串

In [92]: re.findall('\"hello\"','he said "hello"')

Out[92]: ['"hello"']

In [93]: re.findall(r'"hello"','he said "hello"')

Out[93]: ['"hello"']

贪婪 & 非贪婪

贪婪模式:在默认情况下,正则表达式是贪婪模式,即使用 * + ? 的时候,都尽可能多的向后匹配内容

示例:

In [94]: re.findall(r'ab*','abbbbbbbbbbbbcd')

Out[94]: ['abbbbbbbbbbbb']

In [95]: re.findall(r'ab','abbbbbbbbbbcd')

Out[95]: ['abbbbb'] #匹配3到5个,结果匹配5个

非贪婪模式:尽量少的匹配内容

贪婪 -> 非贪婪:贪婪后面加 ?

* -> *?

+ -> +?

? -> ??

-> ?

示例:

In [96]: re.findall(r'ab*?','abbbbbbbbbbbbcd')

Out[96]: ['a']

In [97]: re.findall(r'ab?','abbbbbbbbbbcd')

Out[97]: ['abbb']

正则表达式的分组:

*正则表达式可以分组,分组的标志即为(),每个括号中的内容,是整体正则表达式的一个子组,表达了一个小的整体 #只要加括号就是子组

*子组可以影响 * + ? {} 的重复行为,当重复时,把子组当作整体进行对待

示例:

In [100]: re.search('(ab)*','abbsdgfk').group()

Out[100]: 'ab'

In [101]: re.search('(ab)+','ababasdgfk').group()

Out[101]: 'abab'

*当有多个子组的时候,从外到内,从左到右,称为第一子组,第二子组,第三子组。。。

子组示例:

In [102]: re.search('(a(bc)de(fg)hij)','abcdefghijk').group() #默认是0

Out[102]: 'abcdefghij'

In [103]: re.search('(a(bc)de(fg)hij)','abcdefghijk').group(0)

Out[103]: 'abcdefghij'

In [104]: re.search('(a(bc)de(fg)hij)','abcdefghijk').group(1)

Out[104]: 'abcdefghij'

In [105]: re.search('(a(bc)de(fg)hij)','abcdefghijk').group(2)

Out[105]: 'bc'

In [106]: re.search('(a(bc)de(fg)hij)','abcdefghijk').group(3)

Out[106]: 'fg'

*可以给组起一个名字,称为捕获组 #将来在框架中可能会用到

格式:(?Pregex),其中name就是给组起的名字

调用格式:(?P=name)name是要调用的子组名称

例:

’hello (?Pkitty)’ 给kitty正则表达式的子组起了个名字cat

In [107]: re.search('hello (?Pkitty)','hello kitty').group()

Out[107]: 'hello kitty'

In [110]: re.search('hello (?Pkitty) (?P=cat)','hello kitty kitty').group()

Out[110]: 'hello kitty kitty'

练习:

1.匹配长度为8-10位的密码,必须以字母开头,密码可以是数字、字母、下划线组成

re.findall(‘^[a-zA-Z][_a-zA-Z0-9]$’,’x123456789’)

^[a-zA-Z]\w

2.匹配身份证号

re.findall(‘^[0-9]X$’,’12345678901234567X’)

\d(\d|X)

In [120]: re.search('\d(\d|X)','370786199503141212').group()

Out[120]: '370786199503141212'

3.浮点数

^-?\d+\.\d+$

In [111]: re.search('^-?\d+\.\d+$','12.36').group()

Out[111]: '12.36'

4.整数或浮点数

^-?\d+(\.\d+)?$

In [116]: re.search('^-?\d+(\.\d+)?$','-12.8').group()

Out[116]: '-12.8'

re模块

compile()

功能:生成一个正则表达式对象

参数:传入一个正则表达式

返回值:返回正则表达式相应的对象

*正则表达式对象的一些属性函数 同 re模块可调用的一些函数名相同,用法相近

*这些函数多为常用的匹配显示函数

*使用的区别上只是用re直接调用的时候,第一个参数需要传入正则表达式,使用compile对象调用的时候则不用

示例:

In [121]: re.findall('\d','123')

Out[121]: ['123']

In [124]: obj = re.compile('\d')

In [125]: obj.findall('123')

Out[125]: ['123']

使用正则表达式对象obj调用时:(详见regex.py)

findall(string)

功能:获取字符串中能被正则表达式匹配的内容

参数:目标字符串

返回值:

将匹配到的内容以列表形式返回

当正则表达式有分组的时候,则每一项会显示每个分组匹配到的内容

示例:

import re

pattern = r'(hello) (\w+)'

# 获取正则表达式对象

obj = re.compile(pattern)

L = obj.findall('hello world hello ketty')

print('findall:', L)# [('hello', 'world'), ('hello', 'ketty')]

split()

功能:将一个字符串,按照正则表达式进行分割

参数:要分割的字符串

返回值:分割后的内容放入一个列表返回

示例:

L1 = re.split(r'\s+', 'hello world nihao China')

# ['hello', 'world', 'nihao', 'China']

sub(replacestr,string,count=0)

功能:使用replacestr的内容,替换string字符串中能被正则表达式匹配的部分

参数:

replacestr:替换内容

string:要匹配的字符串

count:默认情况下替换所有匹配到的部分;如果赋值,表示最多替换count处

返回值:返回替换后的字符串

示例:

s = re.sub(r'[A-Z]', '###', 'Hello World Nihao', count=2)

# sub: ###ello ###orld Nihao

subn()

同sub,只是返回值中多一个实际替换的个数

示例:

s1 = re.subn(r'[A-Z]', '###', 'Hello World Nihao', count=5)

# sub: ('###ello ###orld ###ihao', 3)

match(string)

功能:匹配一个字符串,得到匹配结果

参数:要匹配的字符串

返回值:匹配到返回一个match object,没有匹配到返回None

*只有当正则表达式匹配的内容为字符串的开头的时候,才能匹配到,并且当有多处的时候,只能匹配一处

示例:

import re

# 获取正则表达式对象

re_obj = re.compile(r'foo')

match_obj = re_obj.match('foo is a fun')

print(match_obj) #

print(match_obj.group()) # foo

match_obj2 = re_obj.match('this is my food')

print(match_obj2) #None

print(match_obj2.group()) #抛出异常

search()

同match

区别:可以匹配任意位置,且也是只匹配一处

示例:

re_obj = re.compile(r'foo')

search_obj = re_obj.search('this is my food')

print(search_obj) #

print(search_obj.group()) # foo

finditer()

同findall

区别:返回一个迭代对象,每个迭代对象都是一个match object

示例:

re_obj = re.compile(r'foo')

for i in re_obj.finditer('foo ! this is my food,foo'):

print(i)

print(i.group()) # 打印三次foo

match_obj的属性和函数:(详见regex2.py)

属性:

re:获取对应的正则表达式

pos:获取目标字符串的开始位置

endpos:获取目标字符串结尾位置

lastgroup:最后一组名称

lastindex:最后一组是第几组

示例:

import re

re_obj = re.compile('(ab)cd(?Pef)')

mobj = re_obj.search('hi,abcdefghij')

# mobj属性

print(mobj.re) # 获取对应的正则表达式 re.compile('(ab)cd(?Pef)')

print(mobj.pos) # 获取目标字符串开始位置 0

print(mobj.endpos) # 获取目标字符串结尾位置 13

print(mobj.lastgroup) # 最后一组名称 dog

print(mobj.lastindex) # 最后一组是第几组 2

函数:

start():获取匹配到的字符串的开始位置

end():获取匹配到的字符串的结束位置

span():获取匹配到的字符串的起止位置

示例:

import re

re_obj = re.compile('(ab)cd(?Pef)')

mobj = re_obj.search('hi,abcdefghij')

# mobj属性函数

print(mobj.start()) # 获取匹配到的字符串的开始位置 3

print(mobj.end()) # 获取匹配到的字符串的结束位置 9

print(mobj.span()) # 获取匹配到的字符串的起止位置(3,9)

显示匹配结果:

group()

功能:显示匹配到的字符串

参数:

如果不加,默认为0,表示返回整体的匹配结果;

如果加一个数字,表示返回对应的组的匹配结果,如果越界会报错

返回值:返回相应的匹配结果

示例:

import re

re_obj = re.compile('(ab)cd(?Pef)')

mobj = re_obj.search('hi,abcdefghij')

print(mobj.group()) # abcdef

print(mobj.group(1)) # ab

print(mobj.group(2)) # ef

# print(mobj.group(3)) # 报错

groups()

功能:得到所有组匹配到的内容,以一个元组返回

参数:无

示例:

# 以元组的形式返回全部组的内容

print(mobj.groups()) # ('ab', 'ef')

groupdict()

功能:获取所有捕获组匹配内容,以字典返回(捕获组:起了名字的组),键为组名,值为匹配到的内容。

参数:无

示例:

# 返回所有捕获组内容

print(mobj.groupdict()) # {'dog': 'ef'}

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180301G1J61I00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券