python基础

正则表达式

2018-12-19  本文已影响0人  不忘初心的女孩

1.正则概述
学正则就是为了提取源代码中想要的数据。正则不是某一门语言,所有的都有正则,规则基本上都一样。Python自1.5之后增加了re 模块,提供了正则表达式模块,re 模块使python 语言拥有了全部的正则 表达式功能。
2.re模块简介
python中为安装re,用pip 包管理工具下载安装
①re.match函数
原型:match(patttern,string,flags=0)
参数:
pattern:匹配的正则表达式
string:要匹配的字符串
flags:标志位,用于控制正则表达式的匹配方式,值如下

re.I 忽略大小写
re.S 使. 匹配包括换行符在内的所有字符
re.M 多行匹配,影响 ^ 和 $
re.L 做本地化识别
re.U 根据Unicode字符集解析字符,影响\w \W \b \B
re.X 使我们以更灵活的格式理解正则表达式
功能:尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,返回None

import re
print(re.match("www","www.baidu.com"))#输出结果:<_sre.SRE_Match object; span=(0, 3), match='www'>
print(re.match("www","ww.baidu.com"))#输出结果:None
print(re.match("www","baidu.www.com"))#输出结果:None
print(re.match("www","wwW.baidu.com"))#输出结果:None
print(re.match("www","wwW.baidu.com",flags=re.I))#输出结果:#输出结果:<_sre.SRE_Match object; span=(0, 3), match='wwW'>
#扫描整个字符串,返回从起始位置成功的匹配
print(re.match("www","www.baiduwww.com"))#输出结果:<_sre.SRE_Match object; span=(0, 3), match='www'>
print(re.match("www","www.baidu.com").span())#输出结果:(0, 3)   ,注意  (.match不能用)

②re.search函数 match 只判断起始位置

原型:search(patttern,string,flags=0)
参数:
pattern:匹配的正则表达式
string:要匹配的字符串
flags:标志位,用于控制正则表达式的匹配方式
功能:扫描整个字符串,并返回第一个成功的匹配

print(re.search("sunck","good man is sunck!sunck is nice"))#<_sre.SRE_Match object; span=(12, 17), match='sunck'>

③re.findall 函数
re.findall函数
原型:findall(patttern,string,flags=0)
参数:
pattern:匹配的正则表达式
string:要匹配的字符串
flags:标志位,用于控制正则表达式的匹配方式
功能:扫描整个字符串,并返回结果列表

print(re.findall("sunck","good man is sunck!sunck is nice") )#['sunck', 'sunck']

3.正则表达式的元字符(元字符:最基本的匹配的字符)
①匹配单个字符与数字
. 匹配除换行符以外的任意字符
[0123456789] []是字符集合,表示匹配方括号中所包含的任意一个字符
[sunck] 匹配“s”,“u”,“n”,"c","k" 中任意一个字符
[a-z] 匹配任意小写字母
[A-Z] 匹配任意大写字母
[0-9] 匹配任意数字,类似[0123456789]
[0-9a-zA-Z] 匹配任意的数字和字母
[0-9a-zA-Z_] 匹配任意的数字,字母和下划线
[^sunck] 匹配除了sunck这几个字母以外的所有字符,中括号里的^称为脱字符,表示不匹配集合中的字符
[^0-9] 匹配所有的非数字字符
[^\d ](在代码中要加[],不加就相当于没有集合啦!) 匹配非数字(有 ^ 号加个集合[],没有 ^ 号,就不用加[])
\d 匹配数字,效果同[0-9]
\D 匹配非数字字符,效果同[^0-9]
\w 匹配数字,字母和下划线,效果同[0-9a-zA-Z]
\W 匹配非数字,字母和下划线,效果同[^0-9a-zA-Z]
\s 匹配 任意的空白符(空格,换行,换页,回车,制表),效果同[ \f\n\r\t]
\S 匹配 任意的非空白符,效果同[^ \f\n\r\t]

print(re.search(".","sunck is a good man "))#<_sre.SRE_Match object; span=(0, 1), match='s'>
print(re.search("[0123456789]","sunck is a good man 3"))#<_sre.SRE_Match object; span=(20, 21), match='3'>
print(re.search("[sunck]","sunck is a good man 3"))#<_sre.SRE_Match object; span=(0, 1), match='s'>
print(re.findall("[^0-9]","sunck is a good man 3"))#['s', 'u', 'n', 'c', 'k', ' ', 'i', 's', ' ', 'a', ' ', 'g', 'o', 'o', 'd', ' ', 'm', 'a', 'n', ' ']
print(re.findall("[^\d ]","sunck is a good man 3"))#['s', 'u', 'n', 'c', 'k', ' ', 'i', 's', ' ', 'a', ' ', 'g', 'o', 'o', 'd', ' ', 'm', 'a', 'n', ' ']
                                                       # ['s', 'u', 'n', 'c', 'k', 'i', 's', 'a', 'g', 'o', 'o', 'd', 'm', 'a', 'n']
print(re.findall(r"^\d ","sunck is a good man 3"))#不加[]是错误的

4.锚字符(边界字符)
^ 行首匹配 (在中括号里叫脱),和在[ ]里的^不是一个意思
$ 行尾匹配

\A 匹配字符串开始,它和 ^ 的区别是:\A只匹配整个字符串的开头,即使在re.M模式下也不会匹配它行的行首(^每一行行首都 匹配)

\Z 匹配字符串结束,它和$的区别是:\Z只匹配整个字符串的结束,即使在re.M模式下也不会匹配它行的行尾
\b 匹配一个单词的边界,也就是指单词和空格间的位置
‘er\b’可以匹配never,不能匹配nerve
\B 匹配非单词边界

print(re.search("^sunck","sunck is good man"))#<_sre.SRE_Match object; span=(0, 5), match='sunck'>
print(re.search("sunck$","sunck is good man"))#None
print(re.search("^sunck","sunck is good man"))#<_sre.SRE_Match object; span=(0, 5), match='sunck'>
print(re.search("\Asunck","sunck is good man"))#<_sre.SRE_Match object; span=(0, 5), match='sunck'>
print(re.findall("^sunck","sunck is good man\nsunck is a nice man",re.M))#['sunck', 'sunck']
print(re.findall("\Asunck","sunck is good man\nsunck is a nice man",re.M) )#['sunck']
print(re.search(r"er\b","never") )#<_sre.SRE_Match object; span=(3, 5), match='er'>
print(re.search(r"er\b","nerve") )#None
print(re.search(r"er\B","never") )#None
print(re.search(r"er\B","nerve") )#<_sre.SRE_Match object; span=(1, 3), match='er'>

5.匹配多个字符
(说明:下方的 x、y、z均为假设的普通字符,m、n非负整数,不是正则表达式的元字符)

(xyz) 匹配小括号内的xyz(作为一个整体去匹配)
x? 匹配0个或者1个x
x* 匹配0个或者 任意多个x (.* 表示匹配0个或者任意多个字符(换行符除外))
x+ 匹配至少一个x
x{n} 匹配确定的n个x(n是一个非负整数)
x{n,} 匹配至少n个x
x{n,m} 匹配至少n个最多m个x,注意n<=m
x|y |表示或,匹配的是x或y

print(re.findall(r"(sunck)","sunckgood is a good man,sunck is a nice man"))#['sunck', 'sunck']
print(re.findall("(sunck)","sunckgood is a good man,sunck is a nice man"))#['sunck', 'sunck'] 加个r是为了以后出现转义字符,当然在这个可以不加
print(re.findall("o?","sunck is a good man,sunck is a nice man"))#['', '', '', '', '', '', '', '', '', '', '', '', 'o', 'o', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
print(re.findall(r"a?","aaa"))#['a', 'a', 'a', '']    非贪婪匹配(尽可能少的匹配)
print(re.findall(r"a*","aaabaacaaaa"))#['aaa', '', 'aa', '', 'aaaa', '']    贪婪匹配(尽可能多的匹配)
print(re.findall(r".*","aaabaacaaaa"))#['aaabaacaaaa', '']
# print(re.findall(r"a+","至少有一个a才行"))
print(re.findall(r"a+","aaaajdddjaaaajjjaaaaa"))#['aaaa', 'aaaa', 'aaaaa'] 贪婪匹配(尽可能多的匹配)
print(re.findall(r"a{3}","aaaajdddjaaaajjjaaaaa"))#['aaa', 'aaa', 'aaa']
print(re.findall(r"a{3}","aa"))#  []表示什么也没有
print(re.findall(r"a{3}","aaaaaa"))#['aaa', 'aaa']
print(re.findall(r"a{3,}","aaaaaabaaaa"))#['aaaaaa', 'aaaa']    婪匹配(尽可能多的匹配)
print(re.findall(r"a{3,6}","aaaaaaa"))#['aaaaaa']
print(re.findall(r"a{3,6}","aaaabaaa"))#['aaaa', 'aaa']
print(re.findall(r"(s|S)unck","sunck--Sunck"))#['s', 'S']
print(re.findall(r"((s|S)unck)","sunck--Sunck"))#[('sunck', 's'), ('Sunck', 'S')]   加括号就变成了一个组,所以输出结果为一个组的形式

例子:需求,提取sunck.........man.

# 需求,提取sunck.........man.
# *?  +?  x? 最小匹配,通常都是尽可能多的匹配,可以使用这种方式解决贪婪匹配
str="sunck is a good man!sunck is a nice man !sunck is a very handsome man"
print(re.findall(r"^sunck.*man$",str))#['sunck is a good man!sunck is a nice man !sunck is a very handsome man']
print(re.findall(r"^sunck.*?man$",str))#['sunck is a good man!sunck is a nice man !sunck is a very handsome man']还是一个因为是有^$
print(re.findall(r"sunck.*?man",str))#['sunck is a good man', 'sunck is a nice man', 'sunck is a very handsome man']   3个

# (?:x)     类似(xyz),但不表示一个组




# 注释:   /*   part1   */    /*   part2   */
# //*   第二个/为转义字符,/*就代表*的意思,  第三个/也是转义字符
print(re.findall(r"//*.*/*/",r"/*   part1   */    /*   part2   */"))#['/*   part1   */    /*   part2   */']
print(re.findall(r"//*.*?/*/",r"/*   part1   */    /*   part2   */"))#['/*   part1   */', '/*   part2   */']     2 个

例2判断手机号

# --------------判断手机号-----------------------
def checkphone2(str):
    pat=r"^1[3578]\d{9}$"
    res=re.match(pat,str)
    print(res)
print(checkphone2("13912345678") )#<_sre.SRE_Match object; span=(0, 11), match='13912345678'>
print(checkphone2("139123456785") )
print(checkphone2("139123456785") )
print(checkphone2("139123a6785") )
print(checkphone2("239123456785") )


def checkphone2(str):
    pat=r"^1(([3578]\d)|(47))\d{8}$"
    res=re.match(pat,str)
    print(res)
print(checkphone2("13912345678"))  # <_sre.SRE_Match object; span=(0, 11), match='13912345678'>
print(checkphone2("139123456785") )
print(checkphone2("139123456785") )
print(checkphone2("139123a6785") )
print(checkphone2("239123456785"))

6.re模块深入
字符串切割

# =========字符串切割=----------------
strl="sunck     is a good man"
print(strl.split(" "))#['sunck', '', '', '', '', '', '', '', 'is', 'a', 'good', 'man']  以空格切割   split括号里什么都不写默认是空格
print(re.split(r" +",strl))#['sunck#is', 'a', 'good', 'man']   至少一个空格作为切割福

7.re.finditer函数
re.finditer函数(防止找出来的数据过多,增大内存,所以用迭代器)
原型:finditer(patttern,string,flags=0)
参数:
pattern:匹配的正则表达式
string:要匹配的字符串
flags:标志位,用于控制正则表达式的匹配方式
功能:与findall(所有的返回一个列表)类似,扫描整个字符串,返回的是一个迭代器

iter:把可迭代对象转成迭代器
与findall的区别:finditer返回的迭代器需要用next 去访问每一个元素

import re
str3="sunck is a good man! sunck is a nice man! sunck is a handsome man"
d=re.finditer(r"(sunck)",str3)
while True:
    try:
        l=next(d)
        print(l)
    except StopIteration as e:
        break

8, 字符串的替换和修改
sunck is a good good good man
sub(pattern, repl, string, count=0)
subn(pattern, repl, string, count=0)
pattern:正则表达式(规则)
repl:指定的用来替换的字符串
string:目标字符串
count:最多替换次数
flags:标志位,用于控制正则表达式的匹配的方式
功能:在目标字符串中,以正则表达式的规则匹配字符串,再把他们替换成指定的字符串。可以指定替换的次数,如果不指定,替换所有的匹配字符串。
区别::前者返回一个被替换的字符串,后者返回一个元组,第一个元素是被替换的字符串,第二元素表示被替换的次数

#   -----------------字符串的替换和修改--------------------
str5 = "sunck is a good good good man"
print(re.sub(r"(good)","nice",str5))#print(re.sub(r"(good)","nice",str5))#
print(type(re.sub(r"(good)","nice",str5)))#<class 'str'>
print(re.subn(r"(good)","nice",str5))#('sunck is a nice nice nice man', 3)
print(type(re.subn(r"(good)","nice",str5)))#<class 'tuple'>

9.分组(重要)
分组:
概念:除了简单的判断是否匹配之外,正则表达式还有提取字串的功能。用()表示的就是提取分组

# --------------分组----------------
str6 = "010-54327654"
m = re.match(r"(\d{3})-(\d{8})",str6)
# 使用序号获取对应组的信息,group(0)一直代表的就是原始字符串
print(m.group(0))#010-54327654
print(m.group(1))#010
print(m.group(2))#54327654
# 查看匹配的各组的情况
print(m.groups() )#('010', '54327654')


# 当有多个括号时,group先最外层在里层
str6 = "010-54327654"
m = re.match(r"((\d{3})-(\d{8}))",str6)
print(m.group(0))#010-54327654
print(m.group(1))#010-54327654
print(m.group(2))#010
print(m.group(3))#54327654
print(m.groups() )#('010-54327654', '010', '54327654')



# ----------给组取名字 ?p< > ----------
str6 = "010-54327654"
m = re.match(r"(?P<first>\d{3})-(?P<last>\d{8})",str6)
print(m.group(0))#010-54327654
print(m.group(1))#010
print(m.group("first"))#010
print(m.group(2))#54327654

10.编译
把正则表达式编译成一个正则对象,用时直接用对象就可以啦
编译:当我们使用正则表达式时,re模块会干两件事
1、编译正则表达式,如果正则表达式本身不合法,会报错
2、用编译后的正则表达式去匹配对象
compile(pattern,flags=0)
pattern:要编译的正则表达式

# ----------编译===================
import re
pat = r"(1([3578]\d)|(47)d{8})"
print(re.match(pat,"13600000000"))
# 编译成正则对象
re_telephon = re.compile(pat)
print(re_telephon.match("13600000000"))

# pat=r'(1([34578]\d|(47))\d{8})'
# re_telephone=re.compile(pat)
# print(re.match(pat,'13600000000')) #原来的写法
# print(re_telephone.match('13600000000'))  #现在的写法

re模块调用
re对象调用
re.match()
re.match(pattern,string,flags=0)
re_telephon.match(string)

re.search()
re.search(pattern,string,flags=0)
re_telephon.search(string)

re.findall(pattern,string,flags=0)
re_telephon.findall(string)
re.findall()

re.finditer(pattern,string,flags=0)
re_telephon.finditer(string)
re.finditer()
re.split(pattern,string,maxsplit=0,flags=0)
re_telephon.split(string,maxsplit=0(最大的一个切割数))
re.split()

re.sub(pattern,repl,string,count=0,flags=0)
re_telephon.sub(repl,string,count=0)
re.sub()
re.sub(pattern, repl, string, count=0, flags=0)
re_telephone.sub(repl, string, count=0, flags=0)
re.subn()
re.subn(pattern, repl, string, count=0, flags=0)
re_telephone.subn(repl, string, count=0, flags=0)

11.re.compile函数
使用re.compile
re模块中包含一个重要函数是compile(pattern [, flags]) ,该函数根据包含的正则表达式的字符串创建模式对象。可以实现更有效率的匹配。在直接使用字符串表示的正则表达式进行search,match和findall操作时,python会将字符串转换为正则表达式对象。而使用compile完成一次转换之后,在每次使用模式的时候就不用重复转换。当然,使用re.compile()函数进行转换后,re.search(pattern, string)的调用方式就转换为 pattern.search(string)的调用方式。
1.其中,后一种调用方式中,pattern是用compile创建的模式对象。如下:

import re
some_text = 'a,b,,,,c d'
reObj = re.compile('[, ]+')
print(reObj.split(some_text))#['a', 'b', 'c', 'd']

2.不使用re.compile
在进行search,match等操作前不适用compile函数,会导致重复使用模式时,需要对模式进行重复的转换。降低匹配速度。而此种方法的调用方式,更为直观。如下:

import re
some_text = 'a,b,,,,c d'
re.split('[, ]+',some_text)#['a', 'b', 'c', 'd']

详细解释:

import re
rec_data="+MIPLOBSERVE:0,68220,1,3303,0,-1"
msgidRegex = re.compile(r',(\d)+,')
mo = msgidRegex.search(rec_data)
print (mo.group())#,68220,

② 分析以上代码,首先是导入re模块,然后调用compile函数,compile(pattern[,flags] ) 根据包含正则表达式的字符串创建模式对象。其中有一些是特殊字符,如果想使用特殊字符需要前面加\,比如1中的()只是括号,不是字符

. ^ $ * + ? { } [ ] \ | ( )
③ \d,意思是整数类型,1中的+号和()都是特殊字符,所以生成的模式对象就是两个逗号之间有一个数字的,然后在search的时候就会匹配,正则表达式中,group()用来提出分组截获的字符串,所以最后得到的是68220

参考资料:
python语法re.compile模块介绍
python 中的 re.compile 函数

上一篇 下一篇

猜你喜欢

热点阅读