正则
概述:
正则表达式,Regular Expression,缩写regex、regexp、RE
正则表达式是文本处理极为重要的技术,用它可以对字符串按照某种规则进行检索、替换
1970年,Unix之父ken Thompson将正则表达式引入到Unix中文本编辑器ed和grep命令中,由此正则表达式普及开来
1980年后,perl语言对Henry Spencer编写的库,扩展了很多新的特性。1997年开始,Philip Hazel开发除了PCRE(perl compatible regular expressions),它被PHP和HTTPD等工具采用。
正则表达式应用极其广泛,shell中处理文本的命令、各种高级编程语言都支持正则
分类:
- BRE:基本正则表达式,grep sed vi等软件支持。vim有扩展
- ERE:扩展正则表达式,egrep(grep -E)、sed -r等
- PCRE:几乎所有高级语言都是PCRE的方言或变种。python从1.6开始使用SRE正则表达式引擎,可以认为是PCRE的子集,见模块re
基本语法
元字符
- . 匹配除换行符外任意一个字符
- [abc]:字符集合,只能表示一个字符的位置,匹配所有包含的任意一个字符:[abc]匹配plain中的‘a’
- [^abc]:字符集合,只能表示一个字符的位置,匹配除去集合内字符的任意一个字符:[abc]匹配plain中的‘p’、‘l’、‘i’、‘n’
- [a-z]:字符范围,也是一个集合,表示一个字符位置,匹配所包含的任意一个字符
- [^a-z]:匹配除去集合内字符的任意一个字符
- \b:匹配单词的边界:\bb在文本中找到单词b开头的b字符
- \B:不匹配单词的边界:t\B包含t的单词但是不以t结尾的t字符,如write
- \d:[0-9]匹配一位数字
- \D:[^0-9]匹配一位非数字
- \s:匹配1位空白字符,包括换行符、制表符、空格
- \S:匹配1位非空白字符
- \w:匹配[a-zA-Z0-9_],包括中文的字
- \W:匹配\w之外的字符
单行模式:.可以匹配所有字符,包括换行符^表示整个字符串的开始,$表示整个字符串的结尾。开始指的是\n后紧接着下一个字符,结束指的是/n前的字符
- 转义:凡是在正则表达式中有特殊意义的符号,如果想使用它的本意,请使用\转义。反斜杠自身,则使用\。\r,\n还是转义后代表回车换行
重复
- * :表示前面的正则表达式会重复0次或多次:e\w*单词中有e然后后面非空白字符
- +:表示前面的正则表达式重复至少1次
- ?:表示前面的正则表达式会重复0次或1次
- {n}:重复固定n次
- {n,}:重复至少n次 {1,}等价于+ | {0,}等价于啊* | {0,1}等价于?
- {n,m}:重复n到m次
- x|y:匹配x或者y
- 捕获:
- (pattern):使用小扩号指定一个子表达式,也叫分组。捕获后会自动分配组从1开始可以改变优先级
- \数字:匹配对应分组
- (?:pattern):如果仅仅为了改变优先级,就不需要捕获分组
- (?\<name\>exp)、(?’name’exp):分组捕获,但是可以name访问分组python语法必须是(?P\<name\>exp)
- 零宽断言
- (?=exp):断言exp一定在匹配的右边出现,也就是说断言后面一定跟一个exp:f(?=oo)f后面一定有oo出现
- (?<=exp):断言exp一定出现在匹配的左边,也就是说前面一定有个exp前缀:(?<=f)ood,ood前一定有f出现
- 负向零宽断言:
- (?!exp):断言exp一定不会出现在右侧,也就是说断言后面一定不是exp
- (?>!exp):断言exp一定不能出现在左侧,也及时说断言前面一定不能是exp:(?<!f)ood ood的左边一定不是f</li>
- (?#comment):注释 例如:f(?=oo)(?#这个后断言不捕获)
分组和捕获是同一个意思,能用简单表达式,就不要用复杂的表达式
贪婪与非贪婪
- 默认是贪婪模式,也就是说尽量匹配更长的字符串
- 非贪婪模式很简单,在重复的符号后面加一个?问好,就是尽量少匹配了
- *?:匹配任意次,但尽可能少重复
- +?:匹配至少一次,但尽可能少重复
- ??:匹配0次或一次,但尽可能少重复
- {n,}?:匹配至少n次,但尽可能少重复
- {n,m}?:匹配至少n次,至多m次,但尽可能少重复
- 引擎选项:
- IgnoreCase:匹配时忽略大小写。re.l/re.IGNORECASE
- Singleline:单行模式:.可以匹配所有字符,包括\n。re.S/re.DOTALL
- Multiline:多行模式:^行首、$行尾。re.M/re.MULTILINE
- IgnorePatternWhitespace:忽略表达式中的空白字符,如果要使用空白字符用转义,#可以用来左注释。re.X/re.VERBOSE
练习:
匹配身份证号:
\d{10}[0-9]{2}([0-2]\d|3[01])\d{3}(\d|x)
Python的正则表达式
- Python使用re模块提供了正则表达式处理的能力
- 常量:
- re.M/re.MULTLINE:多行模式
- re.S/re.DOTALL:单行模式
- re.l/re.IGNORECASE:忽略大小写
- re.X/re.VERBOSE:忽略表达式中的空白字符
- 使用|位或运算开启多种选项
- 方法:
- 编译:
- re.compile(pattern,flags=0)
- 设定flags,编译模式,返回正则表达式对象regex
- pattern就是正则表达式字符串,flags是选项。正则表达式需要被编译,为了提高效率,这些编译后的结果被保存,下次使用同样的pattern的时候,就不需要再次编译。
- re的其他方法为了提高效率都调用了编译方法,就是为了提速
单次匹配:
- re.match(pattern,string,flags=0)
- regex.match(string,pos[,endpos])
- match匹配从字符串的开头匹配,regex对象match方法可以重设定开始位置和结束位置。返回match对象
- re.search(pattern,string,flags=0)
- regex.search(string[,pos[,endpos]])
- 从头搜索直到第一个匹配,regex对象search方法可以重设定开始位置和结束位置,返回match对象
- re.fullmatch(pattern,string,flags=0)
- regex.fullmatch(string[,pos[,endpos]])
- 整个字符串和正则表达式匹配
- 编译:
全部匹配
* re.findall(pattren,string,flag=0)
* regex.findall(string[,pos[,endpos]])
* 对整个字符串,从左至右匹配,返回所有匹配项的列表
* re.finditer(pattern,string,flag=0)
* regex.finditer(string[,pos[,endpos]])
* 对整个字符串,从左至右匹配,返回所有匹配项,返回`迭代器`
* 注意:每次迭代返回的是match对象
#举例:
In [43]: s = ”’bottle\nbag\nbig\napple”’
In [44]: for x in enumerate(s):
…: if x[0] % 8 == 0:
…: print()
…: print(x,end=”)
…: print(‘\n’)
(0, ‘b’)
(8, ‘a’)
(16, ‘p’)
In [45]: result = re.match(‘b’,s)#找不到第一个就不找了
In [46]: print(1,result)
1 <_sre.SRE_Match object; span=(0, 1), match=’b’>
In [47]: result = re.match(‘a’,s)#第一个没找到就返回None
In [48]: print(2,result)
2 None
In [49]: result = re.match(‘^a’,s,re.M)#依然从头找
In [50]: print(3,result)
3 None
In [51]: result = re.match(‘^a’,s,re.S)
In [52]: print(4,result)
4 None
#先编译,然后使用正则表达式对象
In [53]: regex = re.compile(‘a’)
In [54]: result = regex.match(s)
In [55]: print(5,result)
5 None
In [56]: result = regex.match(s,15)#把索引15作为开始找
In [57]: print(6,result)
6 <_sre.SRE_Match object; span=(15, 16), match=’a’>
#search方法
In [3]: s
Out[3]: ‘bottle\nbig\nbag\napple’
In [4]: re.search(‘^b’,s)#扫描找到匹配的第一个位置
Out[4]: <_sre.SRE_Match object; span=(0, 1), match=’b’>
In [6]: re.search(‘^b\w+’,s)
Out[6]: <_sre.SRE_Match object; span=(0, 6), match=’bottle’>
In [7]: re.search(‘^b\w+’,s,re.M)
Out[7]: <_sre.SRE_Match object; span=(0, 6), match=’bottle’>
In [9]: result = re.compile(‘^b’,re.M)#提前编译好再调用
In [10]: result.search(s)
Out[10]: <_sre.SRE_Match object; span=(0, 1), match=’b’>
In [11]: result.search(s,10,20)#提前编译的可以使用pos,endpos
Out[11]: <_sre.SRE_Match object; span=(11, 12), match=’b’>
#fullmatch方法
In [12]: re.fullmatch(‘bag’,s)
In [13]: result = re.compile(‘bag’,re.M)
In [14]: result.fullmatch(s,7,10)#无返匹配结果
In [15]: s
Out[15]: ‘bottle\nbig\nbag\napple’
In [18]: result.fullmatch(s,11,14)#指定索引位置,要完全匹配,多少都不行。末尾是开区间
Out[18]: <_sre.SRE_Match object; span=(11, 14), match=’bag’>
#findall方法,全部匹配
In [19]: re.findall(‘^b’,s)#单行模式下,此处^不是词首而是行首的意思
Out[19]: [‘b’]
In [20]: s
Out[20]: ‘bottle\nbig\nbag\napple’
In [21]: re.findall(‘^b’,s,re.M)#多行模式可以返回所有b开头的行
Out[21]: [‘b’, ‘b’, ‘b’]
In [66]: re.findall(r’\bb\w+\b’,s)#单行模式匹配行中的多个单词
Out[66]: [‘bottle’, ‘bag’, ‘big’]
In [64]: re.findall(‘b\w+’,s)
Out[64]: [‘bottle’, ‘bag’, ‘big’]
#finditer方法,全部匹配并返回生成器对象
In [68]: c = re.finditer(‘b\w+’,s)
In [69]: print(next(c))
<_sre.SRE_Match object; span=(0, 6), match=’bottle’>
In [70]: print(next(c))
<_sre.SRE_Match object; span=(7, 10), match=’bag’>
In [71]: print(next(c))
<_sre.SRE_Match object; span=(11, 14), match=’big’>
匹配替换
- re.sub(pattern,replacement,string,count=0,flags=0)
- regex.sub(replacement,string,count=0)
- 使用pattern对字符串string进行匹配,对匹配项使用repl替换
- replacement可以是string、bytes、function
- re.subn(pattern,replacement,string,count=0,flags=0)
- regex.subn(replacement,string,count=0)
- 同sub返回一个元组(new_string,number_of_sub_made)
#sub举例:
In [79]: s
Out[79]: ‘bottle bag big apple’
In [76]: re.sub(‘a’,’c’,s)
Out[76]: ‘bottle bcg big cpple’
In [77]: regex = re.compile(‘e’)
In [80]: regex.sub(‘mage’,s)
Out[80]: ‘bottlmage bag big applmage
#subn举例:
In [82]: re.subn(‘b’,’Thunk’,s)
Out[82]: (‘Thunkottle Thunkag Thunkig apple’, 3)#返回元组及替换次数
字符串分割
字符串分割函数劣势:不能指定多个字符串进行分割
- re.split(pattern,string,maxsplit=0,flags=0)
- re.split分割字符串
In [114]: s
Out[114]: ‘bottle \n ba|g \nbig’
In [115]: print(s.split())#字符串切割函数无法做到多分隔符分割
[‘bottle’, ‘ba|g’, ‘big’]
In [120]: re.split(‘[\se]’,s,re.M)#通过正则指定多分割符切割
Out[120]: [‘bottl’, ”, ”, ”, ‘ba|g’, ”, ‘big’]
In [121]: re.split(‘[\sb]’,s,re.M)
Out[121]: [”, ‘ottle’, ”, ”, ”, ‘a|g’, ”, ”, ‘ig’]
分组
- 使用小扩号的pattrn捕获的数据被放到了组group中
- match、search函数可以返回match对象;findall返回字符串列表;finditer返回一个个match对象
- 如果pattern中使用了分组,如果有匹配结果,会在match对象中
- 1.使用group(N)方式返回对应分组,1-N是对应的分组,0返回整个匹配的字符串
- 2.如果使用了命名分组,可以使用group(‘name’)的方式取分组
- 3.也可以使用groups()返回所有分组
- 4.使用groupdict()返回所有命名的分组
#group分组
In [137]: regex = re.compile(‘(b\w+)’)
In [138]: regex.match(s)
Out[138]: <_sre.SRE_Match object; span=(0, 6), match=’bottle’>
In [148]: regex.search(s).groups()#groups取出所有分组并返回元组
Out[148]: (‘bottle’,)
In [149]: regex.search(s).group()
Out[149]: ‘bottle’
In [152]: regex = re.compile(‘(b\w+)\s(?P<name2>b\w+)’)#定义分组名称
In [153]: regex.search(s).group()
Out[153]: ‘bottle\nbag’
In [154]: regex.search(s).groups()
Out[154]: (‘bottle’, ‘bag’)
In [157]: regex.search(s).group(‘name2’)#调取名称分组
Out[157]: ‘bag’
In [158]: regex.search(s).group(1)#索引分组
Out[158]: ‘bottle’
In [159]: regex.search(s).groupdict()#将分组转换成字典
Out[159]: {‘name2’: ‘bag’}
#迭代:
In [167]: for x in result:
…: print(type(x),x,x.group(),x.group(‘name2’))
—————————————————————————
TypeError Traceback (most recent call last)
<ipython-input-167-2b12e049a45a> in <module>()
—-> 1 for x in result:
2 print(type(x),x,x.group(),x.group(‘name2’))
TypeError: ‘_sre.SRE_Match’ object is not iterable#match对象不可迭代
In [168]: type(result)
Out[168]: _sre.SRE_Match
In [169]: regex = re.compile(‘(?P<head>b\w+)’)
In [170]: result = regex.finditer(s)#生成一个可迭代对象
In [171]: for x in result:
…: print(type(x),x,x.group(),x.group(‘head’))
<class ‘_sre.SRE_Match’> <_sre.SRE_Match object; span=(0, 6), match=’bottle’> bottle bottle
<class ‘_sre.SRE_Match’> <_sre.SRE_Match object; span=(7, 10), match=’bag’> bag bag
<class ‘_sre.SRE_Match’> <_sre.SRE_Match object; span=(11, 14), match=’big’> big big
作业:(红色标记未完成)
1.匹配邮箱地址,正确的
test@hot-mail.com
v-ip@magedu.com
web.manager@magedu.com.cn
super.user@google.com
a@w-a-com
[\w-]+@[\w-]+\.\w+ #没有匹配w-a-com的那条
test@hot-mail.com
v-ip@magedu.com
manager@magedu.com
user@google.com
2.匹配html标记的内容
<\w\s\w+=\'(?<url>[^’]+)\’\s\w+=\'(?<target>[^’]+)\’>(?<name>\w+)
http://www.magedu.com/index.html’ target=’_blank’>马哥教育
3.判断密码强弱
要求密码必须由10-15位,指定字符串组成:
* 十进制
* 大写字母
* 小写字母
* 下划线
* 要求四种类型的字符串都要出现才算合法的强密码
*
思路:
4.单词统计word count,对samplt.txt进行单词统计,要求使用正则
代码:
本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/88239
评论列表(1条)
朋友,你看的是多少期的内容?怎么会有这么多的知识呢?