正则表达式(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'}
领取专属 10元无门槛券
私享最新 技术干货