import re
re.M 多行模式 位或的意思
parrterm就是正则表达式的字符串,flags是选项,表达式需要被编译,通过语法、策划、分析后卫其编译为一种格式,与字符串之间进行转换
re模块
主要为了提速,re的其他方法为了提高效率都调用了编译方法,就是为了提速
re的方法
单次匹配
re.compile 和 re.match
def compile(pattern, flags=0):
return _compile(pattern, flags)
可看到,re最后返回的是_compile内部方法并对其进行转换
def match(pattern, string, flags=0):
return _compile(pattern, flags).match(string)
使用re模块
import re
s = '0123abc'
regx = re.compile('\d')
print(type(regx))
print(re.match(regx,s))
<class '_sre.SRE_Pattern'>
<_sre.SRE_Match object; span=(0, 1), match='0'>
意思为返回一个模块为match
从头开始匹配扫描,发现匹配一次则不会再继续向下扫描执行
import re
s = '0123abc'
regx = re.compile('\d')
matcher = re.match('\d',s)
#通过regex查看编译后的结果
print(matcher)
matcher.endpos
<_sre.SRE_Match object; span=(0, 1), match='0'>
<class '_sre.SRE_Match'>
每次运行的时候需要调用match
match内部调用了编译方法,意思是说明这个是内部函数,所以compile和match的处理方式是一样的
而match本质是从头向后匹配,找到立刻返回
s = '0123abc'
regx = re.compile('[a|b]')
matcher = regx.match(s)
print(type(matcher))
print(matcher)
<class 'NoneType'>
None
发现是None,match要求必须是从头开始
改进:
s = 'a0123abc'
regx = re.compile('^[a|b]')
matcher = re.match(regx,s)
matcher = regx.match(s)
print(type(matcher))
print(matcher)
<class '_sre.SRE_Match'>
<_sre.SRE_Match object; span=(0, 1), match='a'>
编译后的match方法可以自己定义索引位置,但是compile没有
import re
s = '0123abc'
regex = re.compile('[a|b]')
matcher = re.match('\d',s)
print(type(matcher))
print(matcher)
matcher = regex.match(s,2)
print(matcher)
<class '_sre.SRE_Match'>
<_sre.SRE_Match object; span=(0, 1), match='a'>
search 方法
import re
s = '012abc'
mather = re.search('[ab]',s)
print(mather)
<_sre.SRE_Match object; span=(3, 4), match='a'>
可看到已匹配到a
match和serach对比
match 找到第一个立即返回,位置是从3开始,直接打印,只匹配一次
search 不管从什么位置开始,找到第一个匹配的则立即返回,行为上和match差不多,只不过search是可以不定位置的
一般情况先都为先编译后使用,所以尽量少使用compile
有些情况也是第一次使用匹配的字符,所以如果明确开头是想要的,直接使用match,不然使用search频率比较高
fullmatch 全文匹配
fullmatch相当于正则匹配全场
import re
s = '0123abc'
regx = re.compile('[ab]')
matcher = re.fullmatch('\w',s)
print(matcher)
matcher = regx.fullmatch(s)
print(matcher)
None
None
#改进:
matcher = regx.fullmatch(s,4,5)
print(matcher)
<_sre.SRE_Match object; span=(4, 5), match='a'>
res = re.fullmatch('bag',s)
print(res)
None
由于fullmatch属于全文匹配,所以要么必须有范围,要么必须得知其长度
s = '''bottle\nbag\nbig\nable'''
regex = re.compile('bag')
res = regex.fullmatch(s,7,10) #匹配完全长度
print(res)
<_sre.SRE_Match object; span=(7, 10), match='bag'>
使用全文匹配最好:
・尽量匹配字符
・先切片再匹配
每个字符对应索引不知,将索引获取后进行折行
s = '''bottle\nbag\nbig\nable'''
for k in enumerate(s):
if k[0] % 8 == 0:
print()
print(k,end=' ')
findall
findall 所返回为一个列表
s = '0123abcd'
regx = re.compile('^b\w+')
matcher = regx.findall(s,re.M)
print(type(matcher))
<class 'list'>
找到所有包含b的字符
s = '''bottle\nbag\nbig\nable'''
rest = re.findall('b',s)
print(rest)
['b', 'b', 'b', 'b']
s = '''bottle\nbag\nbig\nable'''
regx = re.compile('^b')
rest = re.findall(regx,s)
print(rest)
['b']
import re
s = '''bottle\nbag\nbig\nable'''
regx = re.compile('^b',re.M)
rest = re.findall(regx,s)
print(rest)
['b', 'b', 'b']
re.M
SRE_FLAG_MULTILINE = 8 # treat target as multiline string
最少匹配一个
s = '0123abcd'
regex = re.compile('[ab]+')
matcher = regex.findall(s) #字节调用regex方法后面跟字符串即可
print(matcher)
['ab']
匹配非数字所有的
s = '0123abcd'
regex = re.compile('\D')
matcher = regex.findall(s)
print(matcher)
['a', 'b', 'c', 'd']
finditer
返回一个可迭代对象
# coding:utf-8
import re
# s = '''bottle\nbag\nbig\nable'''
s = '0123abcd'
regex = re.compile('\D')
matcher = regex.findall(s)
print(matcher)
matcher = regex.finditer(s)
print(type(matcher))
print(matcher)
['a', 'b', 'c', 'd']
<class 'callable_iterator'>
<callable_iterator object at 0x0000000000B87128> #返回一个迭代器
迭代器可以使用next直接跑出来
for i in matcher:
print(i)
<_sre.SRE_Match object; span=(4, 5), match='a'>
<_sre.SRE_Match object; span=(5, 6), match='b'>
<_sre.SRE_Match object; span=(6, 7), match='c'>
<_sre.SRE_Match object; span=(7, 8), match='d'>
regex = re.compile('\D')
matcher = re.match('\d',s)
print(matcher.span())
(0, 1)
re.M 多行模式
import re
s = '''bottle\nbag\nbig\nable'''
regex = re.compile(r'^b\w+',re.M)
matcher = regex.findall(s)
print(matcher)
['bottle', 'bag', 'big']
去掉re.M查看
s = '''bottle\nbag\nbig\nable'''
regex = re.compile(r'^b\w+')
matcher = regex.findall(s)
print(matcher)
['bottle']
筛取以e结尾的行
import re
s = '''bottle\nbag\nbig\nable'''
regex = re.compile(r'^\w+e$',re.M)
matcher = regex.findall(s)
print(matcher)
为了避免出现问题,就用\n的方式进行分割
在边界的时候指定选项re.M
匹配并替换
sub
re.sub 匹配原来的字符并替换,可根据次数进行调整
将每个数字都替换为一个串字符
import re
s = '''bottle\n123\nbag\nbig\nable'''
regx = re.compile('\d')
res = regx.sub('haha',s)
print(res)
bottle
hahahahahaha
bag
big
able
替换一次
res = regx.sub('haha',s,1)
haha23
将big bag 替换
s = '''bottle\n123\nbag\nbig\nable'''
regx = re.compile('\w+g')
res = regx.sub('hh',s)
print(res)
返回了一个新的字符串
hh
hh
使用subn
s = '''bottle\n123\nbag\nbig\nable'''
regx = re.compile('\w+g')
print(regx.subn('ha',s))
返回一个元组
('bottle\n123\nha\nha\nable', 2)
subn会将其全部封装至一个元组中
s = '''os.path([path])'''
regx = re.compile('[.]')
print(type(regx))
print(regx)
<class '_sre.SRE_Pattern'>
re.compile('[.]')
将其替换为空格
newstr = regx.sub(' ', s)
print(newstr)
newstr = regx.subn(' ', s)
print(newstr)
os path([path])
('os path([path])', 1)
字符串分割
re.split() 可匹配模式、字符串、最大切割数
s = '''\
01 bottle
02 bag
03 big1
100 bale
'''
regx = re.compile('^[\s\d]+')
res = re.split(regx,s)
print(res)
['', 'bottle\n02 bag\n03 big1\n100 bale\n']
如果想去掉\n 需要涉及到断言
数字之前是\n
regx = re.compile('\s+|(?<=!\w)\d')
res = re.split(regx,s)
print(res)
['01', 'bottle', '02', 'bag', '03', 'big1', '100', 'bale', '']
如果使用\d+的话,则数字也全部被消除
regx = re.compile('\s+|(?<!\w)\d+')
res = re.split(regx,s)
print(res)
['', '', 'bottle', '', '', 'bag', '', '', 'big1', '', '', 'bale', '']
筛出空格两边的数字
\s+\d+\s+
之前用的是断言方式,有点复杂,现在我们发现一个规律:两头都有空字符,除了第一行
对于023来讲,前有\n
所以认为数字两边都有空白字符的话,则直接匹配并替换
分组
使用小括号的模式捕获的数据存在了组中
match 、search函数可以返回match对象
findall返回字符串列表
finditer返回一个个的match对象
使用group(N)方式对应分组,1-N是对应的分组,0是返回整个字符串
使用group,在match对象中加入分组会返回一个group,返回一个>=0的整数,1代表1号分组 以此类推
import re
s = '''\
01 bottle
02 bag
03 big1
100 bale
'''
import re
s = '''bottle\nbag\nbig1\nbale'''
regex = re.compile('(b\wg)')
matcher = regex.search(s)
print(matcher)
print(matcher.groups())
<_sre.SRE_Match object; span=(13, 16), match='bag'>
('bag',)
0位整个串,如果超出的话不会报错,一直都是0
print(matcher.groups(0))
print(matcher.groups(1))
print(matcher.groups(2))
print(matcher.groups(3))
('bag',)
('bag',)
('bag',)
('bag',)
更改\b开头,并以e结尾
regex = re.compile('(b\w+e)',re.M)
我们用的是search方法,所知匹配一次
查看:
0是表示匹配从b开头,,b不属于元组内,e也不是
regex = re.compile('b(\w+)e',re.M)
('ottl',)
替换为findall
import re
s = '''bottle\nbag\nbig1\nbale'''
regex = re.compile('\b(\w+)e')
matcher = regex.findall(s)
print(matcher.groups(1))
提示:
意思为能匹配到,但是不能用列表的方式进行group(),需要自己处理
改进:
使用finditer,使用迭代器,进行循环
import re
s = '''bottle\nbag\nbig1\nbale'''
regex = re.compile('\b(\w+)(e)')
matchers = regex.finditer(s)
print(matchers)
for matchers in matchers:
print(matchers.groups())
分组匹配的太多,我们仅需要将分组外的抛除
regex = re.compile('b(\w+) (?p<TAIL>e)')
groupdict
用命名则按照索引方式,用了名字照样可以用索引方式同时支持groupdict()
正则匹配练习
匹配邮箱地址
匹配邮箱地址
html标记获取文字
获取<a>标记
改进
更严谨的判断:
看到这里是\w不带等号或者引号
用取非的方式获取
更复杂的实现:
通过分组取出
改进:
如果取得属性,并有引号则用引号取边界并取反
如果url后面有属性参数可以改为:
匹配一个url
\S 一定不出现空格的字符并至少出现1次的,
匹配身份证
判断密码强弱
凡是有非法字符在的话则替换为空,这样会缩减,并判断字符串的长度
\W判断,查看是否有特殊符号,其他全是合法字符,这样的话肯定会扫描出非合法密码
获取别人最少用的_ 符号,也就是必包含它
单词统计
file_path = r'C:\Users\Administrator\Desktop\sample.txt'
s = '''index modules | next | previous | Python 3.5.3 Documentation The Python Standard Library 11. File and Directory Access '''
regex = re.compile('[^-\w]+')
d = defaultdict(lambda:0)
with open(file_path,'r+',encoding='utf-8') as f:
for line in f:
for x in re.split(regex,line):
if len(x) > 0:
d[x] += 1
print(sorted(d.items(),key=lambda x:x[1],reverse=True))
本文出自 “心情依旧” 博客,请务必保留此出处http://yijiu.blog.51cto.com/433846/1980172