Python中正则表达式
一、概述
(一)概念
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
(二)目的
给定一个正则表达式和另一个字符串,我们可以达到如下的目的:
- 给定的字符串是否符合正则表达式的过滤逻辑(称作“匹配”);
例如:邮箱匹配,电话号码匹配 - 爬虫后,可以通过正则表达式,从字符串中获取我们想要的特定部分。
爬虫中解析 HTML 数据
(三)特点:
1 灵活性、逻辑性和功能性非常的强;
2 可以迅速地用极简单的方式达到字符串的复杂控制。
3 对于刚接触的人来说,比较晦涩难懂。
(四)学习方法
1 做好笔记,不要死记硬背
2 大量练习
python 中通过系统库 re 实现正则表达式的所有功能
二、正则表达式符号
(一)普通字符
- 普通字符:一个正则表达式看上去就是一个普通的查找字符串
Str1 = "testing123Test456TESTing789test"
Result1 = re.findall('test',Str1)
# 修饰符re.I,使匹配对大小写不敏感
Result2 = re.findall('test',Str1,re.I)
print("Result1 = %s,Result2 = %s"%(Result1,Result2))
>>>Result1 = ['test', 'test'],Result2 = ['test', 'Test', 'TEST', 'test']
(二)元字符
- 通配符"." --> 匹配除 \n 之外的任何单个字符
# 匹配除 \n 之外的任何单个字符
Str2 = 'testing123\nTESTing456Testing789'
# 匹配 te加2个任意字符
Result3 = re.findall('te..',Str2)
# 匹配任意两个字符
Result4 = re.findall('..',Str2)
# 匹配 t加任意3个字符,忽略大小写
Result5 = re.findall('t...',Str2,re.I)
# re.S,匹配 \n
Result6 = re.findall('..',Str2,re.S)
print("Result3 = %s,Result4 = %s,Result5 = %s"%(Result3,Result4,Result5))
>>>Result3 = ['test'],Result4 = ['te', 'st', 'in', 'g1', '23', 'TE', 'ST', 'in', 'g4', '56', 'Te', 'st', 'in', 'g7', '89'],Result5 = ['test', 'TEST', 'Test']
print("Result6 =",Result6)
>>>Result6 = ['te', 'st', 'in', 'g1', '23', '\nT', 'ES', 'Ti', 'ng', '45', '6T', 'es', 'ti', 'ng', '78']
- 脱字符"^" --> 匹配输入字符串的开始位置
# 匹配输入字符串的开始位置
Str3 = 'tEsting\nTEST\nTest\ntest'
Result7 = re.findall('^te',Str3)
# 多行匹配输入字符串的开始位置,且忽略大小写
Result8 = re.findall('^te',Str3,re.I | re.M)
print("Result7 = %s,Result8 = %s"%(Result7,Result8))
>>>Result7 = [],Result8 = ['tE', 'TE', 'Te', 'te']
- 美元符"$" --> 匹配输入字符串的结束位置
# 匹配输入字符串的结束位置
Str4 = "testing\nTEST\nTesting\ntest"
Result9 = re.findall('st$',Str4)
Result10 = re.findall('st$',Str4,re.I)
Result11 = re.findall('st$',Str4,re.I | re.M)
print("Result9 = %s,Result10 = %s,Result11 = %s"%(Result9,Result10,Result11))
>>>Result9 = ['st'],Result10 = ['st'],Result11 = ['ST', 'st']
- 重复元字符"*,+,?" -->
* 匹配前面的子表达式任意次
+ 匹配前面的子表达式一次或多次(至少一次)
? 匹配前面的子表达式0次或1次
{} 控制匹配前面的子表达式次数
Str5 = "a\nab\nabbc\nabBbbc"
Result12 = re.findall('ab*',Str5)
Result13 = re.findall('ab+',Str5)
Result14 = re.findall('ab?',Str5)
print("Result12 = %s,Result13 = %s,Result14 = %s"%(Result12,Result13,Result14))
>>>Result12 = ['a', 'ab', 'abb', 'ab'],Result13 = ['ab', 'abb', 'ab'],Result14 = ['a', 'ab', 'ab', 'ab']
Result15 = re.findall('ab{0,}',Str5)
Result16 = re.findall('ab{1,}',Str5)
Result17 = re.findall('ab{0,1}',Str5)
print("Result15 = %s,Result16 = %s,Result17 = %s"%(Result15,Result16,Result17))
>>>Result15 = ['a', 'ab', 'abb', 'ab'],Result16 = ['ab', 'abb', 'ab'],Result17 = ['a', 'ab', 'ab', 'ab']
Result18 = re.findall("ab{2}",Str5)
Result19 = re.findall('ab{3}',Str5,re.I)
print("Result18 = %s,Result19 = %s"%(Result18,Result19))
>>>Result18 = ['abb'],Result19 = ['abBb']
- 选择元字符 “|” --> 表示两个表达式选择一个匹配
# 表示两个表达式选择一个匹配
Str6 = "abc\bcd\cde\tacd\tdcghfd"
# 匹配字符"b"或"d"
Result20 = re.findall("b|d", Str6)
# 匹配"bc"或"ac"或"dc"
Result21 = re.findall("[b|a|d]c",Str6)
print("Result20 = %s,Result21 = %s"%(Result20,Result21))
>>>Result20 = ['b', 'd', 'd', 'd', 'd', 'd'],Result21 = ['bc', 'ac', 'dc']
- 字符组 “[]” --> 表示匹配给出的任意字符
# 表示匹配给出的任意字符
Str7 = "test\nTesting\nzoo\naa\nbfds"
# 匹配包含的任意字符
Result22 = re.findall("[eio]",Str7)
# 匹配包含的字符范围
Result23 = re.findall("[e-o]",Str7)
# 回忆脱字符,匹配以[eio]单个字符开头字符
Result24 = re.findall("^[teoa]",Str7,re.M)
print("Result22 = %s,Result23 = %s,Result24 = %s"%(Result22,Result23,Result24))
>>>Result22 = ['e', 'e', 'i', 'o', 'o'],Result23 = ['e', 'e', 'i', 'n', 'g', 'o', 'o', 'f'],Result24 = ['t', 'a']
# 匹配未包含的任意字符
Result25 = re.findall("[^eio]",Str7)
# 匹配未包含的字符范围
Result26 = re.findall("[^e-o]",Str7)
print("Result25 = %s,Result26 = %s"%(Result25,Result26))
>>>Result25 = ['t', 's', 't', '\n', 'T', 's', 't', 'n', 'g', '\n', 'z', '\n', 'a', 'a', '\n', 'b', 'f', 'd', 's'],Result26 = ['t', 's', 't', '\n', 'T', 's', 't', '\n', 'z', '\n', 'a', 'a', '\n', 'b', 'd', 's']
- 转义元字符 “” --> 用来匹配元字符本身时的转义
# 用来匹配元字符本身时的转义
Str8 = "1(23)4+567@qq.com"
Result27 = re.findall("\.|\(|\)|\+",Str8)
print("Result27 = %s"%Result27)
>>>Result27 = ['(', ')', '+', '.']
- 分组元字符 “()” -->将括号之间的表达式定义为组(group),并且将匹配这个子表达式的字符返回
# 将括号之间的表达式定义为组(group),并且将匹配这个子表达式的字符返回
Str10 = "z\nzood\nfood"
# 不加分组,拿到的引号内正则表达式匹配到的字符
Result44 = re.findall("[z|f]o*",Str10)
# 加上分组,返回的将是引号内正则表达式匹配到的字符中()中的内容。
Result45 = re.findall("[z|f](o*)",Str10)
print("Result44 = %s,Result45 = %s"%(Result44,Result45))
>>>Result44 = ['z', 'zoo', 'foo'],Result45 = ['', 'oo', 'oo']
- 非贪婪模式
# 在默认情况下,元字符"*","+","{m,n}"会尽可能多的匹配前面的子表达式,这叫贪婪模式
# 在这些元字符后面加上"?"时,表示非贪婪,即尽可能少的匹配前面的子表达式
Str9 = "abcdecfgcC"
# 贪婪模式
Result28 = re.findall("ab.*c",Str9)
# 非贪婪模式
Result29 = re.findall("ab.*?c",Str9)
print("Result28 = %s,Result29 = %s"%(Result28,Result29))
>>>Result28 = ['abcdecfgc'],Result29 = ['abc']
Result30 = re.findall("ab.+c",Str9)
Result31 = re.findall("ab.+?c",Str9)
print('Result30 = %s,Result31 = %s'%(Result30,Result31))
>>>Result30 = ['abcdecfgc'],Result31 = ['abcdec']
Result32 = re.findall("ab.{0,2}",Str9)
Result33 = re.findall("ab.{0,2}?",Str9)
print("Result32 = %s,Result33 = %s"%(Result32,Result33))
>>>Result32 = ['abcd'],Result33 = ['ab']
(三)预定义字符:元字符"\"与某些字符组合在一起表示特定的匹配含义
- "\d"匹配单个数字,等价于[0-9]
# 3.1"\d"匹配单个数字,等价于[0-9]
Str11 = """孔籽挺,15650199151
Comments (0)
February 9, 2013
楼干明,15650199152
楼关林,15650199153"""
Result34 = re.findall("\d",Str11)
Result35 = re.findall("\d+",Str11)
print("Result34 = %s,Result35 = %s"%(Result34,Result35))
>>>Result34 = ['1', '5', '6', '5', '0', '1', '9', '9', '1', '5', '1', '0', '9', '2', '0', '1', '3', '1', '5', '6', '5', '0', '1', '9', '9', '1', '5', '2', '1', '5', '6', '5', '0', '1', '9', '9', '1', '5', '3'],Result35 = ['15650199151', '0', '9', '2013', '15650199152', '15650199153']
- "\D"匹配任意单个非数字字符,等价于[^0-9]
# 3.2"\D"匹配任意单个非数字字符,等价于[^0-9]
Result36 = re.findall("\D",Str11)
Result37 = re.findall("\D+",Str11)
print("Result36 = %s,Result37 = %s"%(Result36,Result37))
>>>Result36 = ['孔', '籽', '挺', ',', '\n', '\n', 'C', 'o', 'm', 'm', 'e', 'n', 't', 's', ' ', '(', ')', ' ', '\n', 'F', 'e', 'b', 'r', 'u', 'a', 'r', 'y', ' ', ',', ' ', '\n', '楼', '干', '明', ',', '\n', '\n', '楼', '关', '林', ','],Result37 = ['孔籽挺,', '\n\nComments (', ') \nFebruary ', ', ', '\n楼干明,', '\n\n楼关林,']
- "\s"匹配任意单个空白符,包括空格,制表符(Tab),换行符
# 3.3"\s"匹配任意单个空白符,包括空格,制表符(Tab),换行符
Result38 = re.findall("\s",Str11)
Result39 = re.findall("\s+",Str11)
print("Result38 = %s,Result39 = %s"%(Result38,Result39))
>>>Result38 = ['\n', '\n', ' ', ' ', '\n', ' ', ' ', '\n', '\n', '\n'],Result39 = ['\n\n', ' ', ' \n', ' ', ' ', '\n', '\n\n']
- "\S"匹配任意非空白字符
# 3.4"\S"匹配任意非空白字符
Result40 = re.findall("\S",Str11)
Result41 = re.findall("\S+",Str11)
print("Result40 = %s,Result41 = %s"%(Result40,Result41))
>>>Result40 = ['孔', '籽', '挺', ',', '1', '5', '6', '5', '0', '1', '9', '9', '1', '5', '1', 'C', 'o', 'm', 'm', 'e', 'n', 't', 's', '(', '0', ')', 'F', 'e', 'b', 'r', 'u', 'a', 'r', 'y', '9', ',', '2', '0', '1', '3', '楼', '干', '明', ',', '1', '5', '6', '5', '0', '1', '9', '9', '1', '5', '2', '楼', '关', '林', ',', '1', '5', '6', '5', '0', '1', '9', '9', '1', '5', '3'],Result41 = ['孔籽挺,15650199151', 'Comments', '(0)', 'February', '9,', '2013', '楼干明,15650199152', '楼关林,15650199153']
- "\w"匹配除符号以外的单个字母,数字,下划线或汉字
# 3.5"\w"匹配除符号以外的单个字母,数字,下划线或汉字
Result42 = re.findall("\w",Str11)
Result43 = re.findall("\w+",Str11)
print("Result42 = %s,Result43 = %s"%(Result42,Result43))
>>>Result42 = ['孔', '籽', '挺', '1', '5', '6', '5', '0', '1', '9', '9', '1', '5', '1', 'C', 'o', 'm', 'm', 'e', 'n', 't', 's', '0', 'F', 'e', 'b', 'r', 'u', 'a', 'r', 'y', '9', '2', '0', '1', '3', '楼', '干', '明', '1', '5', '6', '5', '0', '1', '9', '9', '1', '5', '2', '楼', '关', '林', '1', '5', '6', '5', '0', '1', '9', '9', '1', '5', '3'],Result43 = ['孔籽挺', '15650199151', 'Comments', '0', 'February', '9', '2013', '楼干明', '15650199152', '楼关林', '15650199153']
三、采用函数
(一)re.match
- 函数使用方法:re.match(pattern,string,flag)
含义:尝试从字符串的起始位置匹配一个模式,成功返回匹配对象,否则返回 None
pattern: 正则表达式
string: 被匹配的字符串
flag: 标志位,表示匹配模式
返回结果中包含匹配对象的下标
Str12 = "www.hhxpython.com"
Result46 = re.match("www",Str12)
Result47 = re.match("hhx",Str12)
print("Result46 = %s,Result47 = %s"%(Result46,Result47))
>>>Result46 = <re.Match object; span=(0, 3), match='www'>,Result47 = None
- 匹配对象
match 函数返回一个匹配对象,通过这个对象可以取出匹配到的字符串和分组字符串
Str13 = 'Good good study, Day day up!'
match_obj = re.match('(?P<aa>.*) (?P<bb>.*) (?P<cc>.*),(.*) (.*) (.*)',Str13)
if match_obj:
print('match_obj.group() =',match_obj.group()) # 返回匹配到的字符串
print('match_obj.group(1) =',match_obj.group(1)) # 返回对应序号分组字符串 从1开始
print('match_obj.group(2) =',match_obj.group(2))
print('match_obj.group(3) =',match_obj.group(3))
print('match_obj.group(4) =',match_obj.group(4))
print('match_obj.group(5) =',match_obj.group(5))
print('match_obj.group(6) =',match_obj.group(6))
else:
print('not found')
print('match_obj.groups() =',match_obj.groups()) # 返回分组字符串元组
print('match_obj.groupdict() =',match_obj.groupdict()) # 按照分组名和分组字符串组成字典 (?P<name>pattern)
>>>match_obj.group() = Good good study, Day day up!
>>>match_obj.group(1) = Good
>>>match_obj.group(2) = good
>>>match_obj.group(3) = study
>>>match_obj.group(4) = Day
>>>match_obj.group(5) = day
>>>match_obj.group(6) = up!
>>>match_obj.groups() = ('Good', 'good', 'study', ' Day', 'day', 'up!')
>>>match_obj.groupdict() = {'aa': 'Good', 'bb': 'good', 'cc': 'study'}
(二)re.search
- re.search(pattern, string, flag)
含义:扫描整个字符串返回第一个成功的匹配对象
pattern: 正则表达式
string: 被匹配的字符串
flag: 标志位,表示匹配模式
Str14 = 'www.hhxpython.com'
Result48 = re.search('www',Str14) # 'www' 就是正则表达式,没有元字符表示匹配字符本身
Result49 = re.search('hhx',Str14)
Result50 = re.search('h', Str14)
print('Result48 = %s,Result49 = %s,Result50 = %s'%(Result48,Result49,Result50))
>>>Result48 = <re.Match object; span=(0, 3), match='www'>,Result49 = <re.Match object; span=(4, 7), match='hhx'>,Result50 = <re.Match object; span=(4, 5), match='h'>
(三)re.sub
- re.sub(pattern, repl, string, count=0, flag)
含义:将表达式匹配到的部分替换为制定字符串,返回替换后的新字符串
pattern: 正则表达式
repl: 用来替换的字符串
string: 被匹配的字符串
count: 替换次数,默认为 0,表示全部替换
flags: 标志位,表示匹配模式
phone = '2004-959-559 # 这是一个国外电话号码'
# 删除字符串中的python注释
num = re.sub('#.*', '', phone)
print('num =',num)
>>>num = 2004-959-559
# 删除连接符号 -
num = re.sub('-', '', num)
print('num =',num)
>>>num = 2004959559
(四)re.findall
- re.findall(pattern, string, flags=0)
含义:在字符串中找到正则表达式匹配的所有子串,返回一个列表,匹配失败则返回空列表
pattern: 正则表达式
string: 被匹配的字符串
flags: 标志位,表示匹配模式
line = 'Good good study, Day day up!'
res1 = re.findall('day', line, re.I)
res2 = re.search('day', line, re.I)
res3 = re.match('day', line, re.I)
print('findall方法的结果', res1)
>>>findall方法的结果 ['Day', 'day']
print('search方法的结果', res2.group())
>>>search方法的结果 Day
print('match方法的结果', res3)
>>>match方法的结果 None
-
match,search,findall 的区别
match 从头开始匹配,成功返回匹配对象,失败返回 None
search 只匹配第一个,成功返回匹配对象,失败返回 None
findall 匹配所有,成功返回所有匹配到的字符串组成的列表,失败返回空列表
(五)re.compile
- re.compile(pattern, [flags])
含义:compile 函数用于编译正则表达式,生成一个正则表达式对象,该对象调用 findall,search,match,sub 等方法
pattern: 正则表达式
flags: 标志位,表示匹配模式
面向对象编程时使用
pattern = re.compile('day', re.I)
res1 = pattern.findall(line)
res2 = pattern.search(line)
res3 = pattern.match(line)
print('findall', res1)
>>>findall ['Day', 'day']
print('search', res2.group())
>>>search Day
print('match', res3)
>>>match None