正则表达式、re模块
常用模块之正则模块
正则表达式与re模块的关系
1.正则表达式是一门独立的技术,任何语言均可使用
2.python中要想使用正则表达式需要通过re模块
有无正则校验的区别,手机号示例
# 纯python代码校验
while True: phone_number = input('please input your phone number : ') if len(phone_number) == 11 \ and phone_number.isdigit()\ and (phone_number.startswith('13') \ or phone_number.startswith('14') \ or phone_number.startswith('15') \ or phone_number.startswith('18')): print('是合法的手机号码') else: print('不是合法的手机号码')
# 正则表达式校验 import re phone_number = input('please input your phone number : ') if re.match('^(13|14|15|18)[0-9]{9}$',phone_number): print('是合法的手机号码') else: print('不是合法的手机号码')
正则适用范围:正则在所有语言中都可以使用,不是Python独有的
正则的作用:匹配大段文本特定的字符
测试正则网站:*http://tool.chinaz.com/regex/*
上面我们说到正则是所有语言中都可以使用的,那么正则究竟有哪些应用场景呢:
1.爬虫
2.数据分析
先来说一下常用匹配模式(元字类)
\w #匹配字符数字及下划线 \W #匹配非字母数字下划线 \s #匹配任意空白字符,等价于[\t\n\r\f] \S #匹配任意非空字符 \d #匹配任意数字,等价于[0-9] \D #匹配任意非数字 \A #匹配字符串开始 \Z #匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串 \z #匹配字符串结束 \G #匹配最后匹配完成的位置 \n #匹配一个换行符 \t #匹配一个制表符 ^ #匹配字符串的开头 $ #匹配字符串的末尾 . #匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符 [...] #用来表示一组字符,单独列出:[amk]匹配'a','m'或'k' [^...] #不在[]中的字符:[^abc]匹配除了a,b,c之外的字符
#量词(*, +, ?) * #匹配0个或多个表达式 + #匹配一个或多个表达式 ? #匹配0个或1个由前面的正则表达式定义的片段,非贪婪匹配方式
{n} #精准匹配n个前面表达式 {n,m} #匹配n到m次由前面的正则表达式定义的片断,贪婪方式 a|b #匹配a或b () #匹配括号内的表达式,也表示一个组
字符组 []
一个字符串里面的表达式都是或的关系
[0-9x] #0或1或2或3或4... 或x
^与$符连用 会精准限制匹配的内容
两者中间写什么 匹配的字符串就必须是什么
多一个不行少一个也不行
^abcd$
a|b 一定要将长的放在前面
abcdef|abc
在正则匹配得时候有贪婪匹配(默认就是贪婪匹配)和非贪婪匹配
贪婪匹配:尽量匹配多的 #\d+
非贪婪匹配:尽量匹配少的 #\d+?
由于正则默认就是贪婪匹配,如何将贪婪匹配变成非贪婪匹配呢?
可以通过在量词后面加上一个?就可以将贪婪匹配变成非贪婪匹配(惰性匹配)
量词必须跟在正则符号的后面
量词只能够限制紧挨着它的那一个正则符号
分组:当多个正则符号需要重复多次的时候或者当做一个整体进行其他操作,那么可以使用分组的形式
分组在正则的语法中就是()
小示例一:
身份证号是一个长度为15或者18个字符的字符串,如果是15位则全部由数字组成,首位不能为0,如果是18位,则前面17位全部是数字,末尾可能是数字或者x,如何去写匹配身份证的正则呢?
^[1-9]\d{14}(\d{2}[0-9x])?$ #[1-9] 匹配1-9之间的一个数字 #\d{14} 匹配14个数字 #(\d{2}[0-9x])? 把这段正则看成一个整体,如果要匹配就匹配三个,匹配不上三个就一个也没有 #\d{2} 匹配两个数字 #[0-9x] 匹配0-9之间的一个数组或者x #? 匹配一个或多个
小示例二:
判断是不是合法的手机号,手机号由11位数字组成,且以13,14,15,16,17,18开头,如何去写正则
纯python判断
# 纯python代码校验 while True: phone_number = input('please input your phone number : ') if len(phone_number) == 11 \ and phone_number.isdigit()\ and (phone_number.startswith('13') \ or phone_number.startswith('14') \ or phone_number.startswith('15') \ or phone_number.startswith('18')): print('是合法的手机号码') else: print('不是合法的手机号码')
根据上面的代码,我们可以看到,要写到很多行的代码,用正则的看就会简单很多,我们一起来看一下吧
import re phone_number = input('please input your phone number : ') if re.match('^(13|14|15|16|17|18)[0-9]{9}$',phone_number): print('是合法的手机号码') else: print('不是合法的手机号码') #^(13|14|15|16|17|18) 以13或14....开头 #[0-9] 以0-9之间的任意数字组成 #{9} 匹配九个 #$ 结尾
re模块
常用方法:
1.findall:查找处字符串中符合正则表达式的全部内容
res = re.findall(('[a-z]+','eva zhangsan lisi')) print(res)
2.search:search只会一句正则查询一次,只要查到了结果,就会立即结束,后面的不会再匹配,serach返回的是一个对象,必须调用group才能看到匹配的结果,如果没有查到结果,返回的是None
res = re.search('.v', 'eva zhangsan lisi') print(res) #这时如果查不到会返回None print(res.group()) #如果没有数据再使用.group()方法查看的话,程序会报错
防止报错可以这样写
res1 = re.search('a','eva egon jason') if res1: print(res1.group())
3.match:match只会匹配字符串的开头部分,当字符串的开头不符合匹配规则的情况下,返回None
res = re.match('.v', 'eva zhangsan lisi') print(res) #这时如果查不到会返回None print(res.group()) #如果没有数据再使用.group()方法查看的话,程序会报错
了解方法:
split:切分
ret = re.split('[ab]', 'abcd') # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割 print(ret) # ['', '', 'cd'] 返回的还是列表
sub:替换
ret = re.sub('\d', 'H', 'eva3egon4yuan4',1) # 将数字替换成'H',参数1表示只替换1个 sub('正则表达式','新的内容','待替换的字符串',n) # 先按照正则表达式查找所有符合该表达式的内容 统一替换成'新的内容' 还可以通过n来控制替换的个数 print(ret) # evaHegon4yuan4
compile:将正则表达式编译成一个正则表达式对象
obj = re.compile('\d{3}') #将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字 ret = obj.search('abc123eeee') #正则表达式对象调用search,参数为待匹配的字符串 res1 = obj.findall('347982734729349827384') print(ret.group()) #结果 : 123 print(res1) #结果 : ['347', '982', '734', '729', '349', '827', '384']
finditer:返回一个存放匹配结果的迭代器
import re ret = re.finditer('\d', 'ds3sy4784a') #finditer返回一个存放匹配结果的迭代器 print(ret) # 返回的是一个可迭代对象 print(next(ret).group()) # 等价于ret.__next__() print(next(ret).group()) # 等价于ret.__next__() print(next(ret).group()) # 等价于ret.__next__() print(next(ret).group()) # 等价于ret.__next__() print(next(ret).group()) # 等价于ret.__next__() print(next(ret).group()) # 等价于ret.__next__() 查出迭代取的范围,直接报错
给正则起别名
res = re.search('^[1-9](\d{14})(\d{2}[0-9x])?$','110105199812067023') #还可以给某一个正则表达式起别名 res = re.search('^[1-9](?P<password>\d{14})(?P<username>\d{2}[0-9x])?$','110105199812067023')
#访问正则的时候可以通过password、username来访问,起别名的方式:?P<别名> print(res.group()) print(res.group('password')) print(res.group(1)) print(res.group('username')) print(res.group(2)) print(res.group(2)) print(res.group(1))
分组优先机制
import re res = re.search('^[1-9]\d{14}(\d{2}[0-9x])?$',110105199812067023) print(res.group()) print(res.group(1)) # 获取正则表达式括号阔起来分组的内容 print(res.group(2)) # search与match均支持获取分组内容的操作 跟正则无关是python机制 # 而针对findall它没有group取值的方法,所以它默认就是分组优先获取的结果 ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com') print(ret) # ['oldboy'] 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可 ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com') # ?:取消分组优先 print(ret) # ['www.oldboy.com']
切分数字的两种格式
\d+ ret=re.split("\d+","eva3egon4yuan") print(ret) #结果 : ['eva', 'egon', 'yuan'] (\d+) ret1=re.split("(\d+)","eva3egon4yuan") print(ret1) #结果 : ['eva', '3', 'egon', '4', 'yuan']