python:15:正则表达式

第一章:python

第15节:正则表达式

1,正则表达式

正则表达式(RE)为高级文本模式匹配,以及搜索-替代等功能提供了基础。
Python通过标准库的re模块支持正则表达式(RE)
>>> import re

2,正则表达式中常见的符号和字符

《python核心编程(第二版)》书中443页记录了常见的正则表达式符号和字符
表15.1 正则表达式中常见的符号和字符
| 记号 | 说明 | 正则表达式样例 |
| literal | 匹配字符串的值 | foo |
| re1|re2 | 匹配正则表达式re1或re2 | foo|bar | #竖线
| . | 匹配任何字符(换行符除外)(空字符除外) | b.b | #点号
| ^ | 匹配字符串的开始 | ^Dear | #上尖角号
| $ | 匹配字符串的结尾 | /bin/*sh$ | #美元符号
| * | 匹配前面出现的正则表达式零次或多次 | [A-Za-z0-9]* | #星号
| + | 匹配前面出现的正则表达式一次或多次 | a-z[]+\.com | #加号
| ? | 匹配前面出现的正则表达式零次或一次 | goo? | #问号
| {N} | 匹配前面出现的正则表达式N次,指定N这个数量 | [0-9]{3} | #大括号中间加一个数字
| {M,N} | 匹配前面出现的正则表达式M次到N次 | [0-9]{5,9} | #大括号中间加两个数字,中间用逗号分隔
| [...] | 匹配字符组里面出现的任意一个字符 | [aeiou] | #中括号中加字符
| [..x-y..] | 匹配从字符x到y中的任意一个字符,“-” | [0-9]或[A-Za-z] |
| [^...] | 不匹配此字符集中出现的任何一个字符,包括某一个范围的字符(如果在此字符集中出现) | [^aeiou] | #在中括号的内部的字符开头加上上尖角号
| (*|+|?|{})? | 用于上面出现的任何匹配方式进行“非贪婪”形式匹配,即以最少的重复匹配次数 | .*?[a-z] |
| ..(...).. | 匹配出现的正则表达式(RE),匹配成功后括号当中的内容保存为子组,即只输出括号当中的内容 | ([0-9]{3})?或f(oo|u)bar |
几种特殊字符
| \d | 匹配任何数字,和[0-9]作用相同(\D是\d的反义:表示匹配任何非数字字符) | data\d或data\d+.txt |
| \w | 匹配任何数字字母字符,和[A-Za-z0-9_]作用相同(\W是\w的反义) | [A-Za-z_]\w+ |
| \s | 匹配任何空白符,和[\n\t\r\v\f]作用相同,(\S是\s的反义) | of\sthe |
| \b | 匹配单词边界\B是\b的反义) | \bThe\b |
| \ | 逐一匹配特殊字符(即,取消该特殊字符的特殊含义,值按照字面匹配) | \.或\\或\* |
| \A | 匹配字符串的起始 | \ADear |
| \Z | 匹配字符串的结束 | Dear\Z |

3,re模块:核心函数和方法

1,概述

模块的函数:comple()
re模块的函数和regex对象的方法:
match(),search(),finditer() - 这两个函数需要利用正则表达式模式pattern匹配字符串,并利用匹配对象的方法group()或groups()输出字符结果
而findall(),split(),sub()通过可直接输出匹配的字符

2,逐一说明每个函数的用法
1,compile()

compile(pattern, flags=0)
作用:对正则表达式模式pattern进行编译,flags是可选标识符,并返回一个regex对象。
主要用法:对要进行匹配的表达式进行编译后,可加快匹配寻找的速度,同时对于同一个表达式在后面的匹配过程中无序多次书写。
例子:
>>> tel=re.compile(r'\d{3,4}-?\d{8}') #这个表达式的作用是匹配固话电话号码,前面数字3位加横线,加后面数字8位;compile的作用是对该正则表达式进行编译。
>>> tel #编译后的对象
<_sre.SRE_Pattern object at 0x0263EBD0>
>>> tel.findall('010-12345678') #编译对象的不同方法,比如findall方法可应用,与常规的re.findall(re.findall(r'\d{3,4}-?\d{8}', '010-12345678'))方法不同之处在于,利用的是compile对象进行寻找。
['010-12345678']
>>> tel.match('010-12345678').group() #同样的re.match方法也可应用
'010-12345678'

2,group()和groups()

写法:
group(num=0):返回全部匹配对象(或指定编号的num子组)(num表示第几个子组)
groups():返回一个包含全部匹配的子组的元组(如果没有成功匹配,就返回一个空元组)
group()方法返回匹配对象是根据要求返回某个特定子组;而groups()会返回一个包含唯一或所有子组的元组。如果正则表达式中没有子组的话,groups()将返回一个空元组;而group()则会返回全部匹配对象
相比于groups(),而group()的方法更为全面,不仅能够返回匹配对象,而且能够制定的返回子组,而groups()只负责返回子组,不负责返回匹配对象,这一点是重要区别
例子:
>>> m=re.match(r'(\w\w\w)-(\d\d\d)', 'abc-123') #这里匹配前三个字母加横线加后三个数字
>>> m.group() #group()输出全部的匹配结果,能够匹配则结果全部输出
'abc-123'
>>> m.group(1) #括号当中的数字,表示输出第几个子组,1表示第一个子组
'abc'
>>> m.group(2) #2表示第二个子组
'123'
>>> m.groups() #将匹配的两个子组全部输出为一个元组
('abc', '123')
如果要匹配的表达式当中不存在子组,则group()返回匹配对象,groups()返回空元组
>>> m=re.match(r'\w\w\w-\d\d\d', 'abc-123')
>>> m.group()
'abc-123'
>>> m.groups()
()

3,match()

match(pattern, string, flags=0)
用正则表达式模式pattern匹配字符串string,flags是可选标识符,如果匹配成功,返回一个匹配对象,匹配失败返回None
match的匹配特定是从字符串string的开头进行匹配一旦要匹配的字符串在匹配模式中间时,匹配会失败
例子:
>>> re.search('foo', 'barfoo')
#要匹配的’foo’在’barfoo’字符串的中间,所以没有输出结果
>>> re.match('foo', 'bar')
无结果,如果输出re.match('foo', 'bar').group() 则会出现AttributeError: 'NoneType' object has no attribute 'group' 报错信息
如果想避免报错可以写成如下形式:
>>> m=re.match('foo', 'bar')
>>> if m is not None: m.group()

>>>

4,search()

search(pattern, string, flags=0)
在字符串string中搜索正则表达式模式pattern的第一次出现,flags是可选的标识符,如果匹配成功,则返回一个匹配对象;否则返回None
search()搜索字符串中的模式首次出现的位置,而非从起始处进行匹配,所以match是匹配,而search是搜索,所以search得到的结果比较多。
例子:
>>> re.search('foo', 'barfoo')
<_sre.SRE_Match object at 0x0209FAA0>
>>> re.search('foo', 'barfoo').group()
'foo'

5,findall()

findall(pattern, string[, flags])
在字符串string中搜索正则表达式模式pattern的所有(非重复)出现,最终结果返回一个匹配对象的列表;如果没有找到匹配结果则返回一个空列表
例如:
>>> re.findall('car', 'car')
['car']
>>> re.findall('car', 'scary')
['car']
>>> re.findall('car', 'carry the barcard to the car')
['car', 'car', 'car']
当正则表达式存在多个子组时,匹配的返回结果是一个元组的列表,元组中每个元素都是一个子组的匹配内容,每一个匹配的列表构成列表元组,而当正则表达式存在一个子组时,则直接返回想要子组内容的匹配结果。
例子:
>>> re.findall('(ab)','ab') #匹配内容只存在一个子组,直接返回想要子组内容的匹配结果
['ab']
>>> re.findall('(ab)((cd)(e))','abcde ab cd e') #匹配ab,cd,e,cde
[('ab', 'cde', 'cd', 'e')]
>>> re.findall('(ab)','abcde ab cd e') #匹配内容只存在一个子组,直接返回想要子组内容的匹配结果
['ab', 'ab']
>>> re.findall('(a(b))','abcde ab cd e') #匹配ab,b
[('ab', 'b'), ('ab', 'b')]

5,sub(),subn()

sub(pattern, repl, string, max=0)
sub()和subn()可进行字符串内容的替换;sub()返回替换后的内容,而subn()则返回替换后的内容和次数,内容和次数构成一个元组
sub('s1', 'str2', 'string3')
s1表示原字符串要被替换的内容
str2表示替换后的内容
string3表示要替换的字符串,即原始字符串
例子:
>>> re.sub('[ae]', 'X', 'abcdef') #表示将字符串’abcdef’中的字母’a’和’e’均替换成’X’
'XbcdXf'
>>> re.subn('[ae]', 'X', 'abcdef') #2是替换了两次
('XbcdXf', 2)
另外注意:re.sub当中的空格,不能用\s表示,如果想把\n替换成空格会失败,所以可用’ ‘(空格)来替换’\n’
>>> re.sub('\n', '\s', 'attnX\nDearX\naa')
'attnX\\sDearX\\saa'
>>> re.sub('\n', ' ', 'attnX\nDearX\naa')
'attnX DearX aa'

6,split()

split(pattern, string, max=0)
根据正则表达式pattern中的分隔符把字符string分割为一个列表,返回成功匹配的列表,最多分割max次(默认是分割所有匹配的地方)
>>> re.split(':', 'str1:str2:str3') #可以按照’:’这个字符来分隔
['str1', 'str2', 'str3']
>>> re.split('\d', 'str1:str2:str3:') #也可以按照’\d’这个表达式分隔
['str', ':str', ':str', ':']

3,贪婪匹配与非贪婪匹配

“?”操作符,表示“非贪婪”匹配,该操作可用在“*”,“+”或“?”等字符的后面,所用是要求正则表达式匹配的字符数量越少越好
例如:
>>> data='4-6-8117159036'
>>> pattern=re.compile('(\d+-\d+-\d+?)') #+表示前面的字符重复1到多次,而加入“?”则希望只重复一次
>>> pattern.findall(data)
['4-6-8']
>>> pattern_long=re.compile('(\d+-\d+-\d+)') #没有“?”,则希望尽可能多的重复
>>> pattern_long.findall(data)
['4-6-8117159036']

4,特殊标识及其作用

| 标识 | 含义 |
| re.S | 使“.”或“*”等能够匹配包括换行符在内的所有字符 |
| re.I | 匹配不区分大小写 |
| re.L | 做本地化识别(locale-aware)匹配 |
| re.M | 可进行多行匹配,这样操作会影响“^”和“$”这两个符号的作用 |
| re.X | 同样表示多行匹配,可应用于三引号当中的字符 |
实例:re.S
>>> re.findall(r'cctv.net', 'cctv\nnet')
[]
>>> re.findall(r'cctv.net', 'cctv\nnet', re.S)
['cctv\nnet']
#加入re.S标识后,“.”能够匹配换行符
实例:re.M
>>> s="""
hell world
world hello
hello world hello
world hehe
"""
>>> s
'\nhell world\nworld hello\nhello world hello\nworld hehe\n'
>>> re.findall(r'^world', s)
[]
>>> re.findall(r'^world', s, re.M)
['world', 'world']
#如果不加入re.M这个标识,“^”只运行单行匹配,但此时s为一个单一的字符串,加入re.M标识后,则运行“^”进行多行匹配。
实例:re.I
>>> re.findall(r'acd', 'AcdAAAcDC')
[]
>>> re.findall(r'acd', 'AcdAAAcDC', re.I) #匹配不区分大小写
['Acd', 'AcD']
实例:re.X
>>> tel=r"""
\d{3,4}
-?
\d{8}
"""
>>> tel
'\n\\d{3,4}\n-?\n\\d{8}\n'
>>> re.findall(tel, '010-12345678')
[]
>>> re.findall(tel, '010-12345678', re.X)
['010-12345678']
re.X与re.M的作用基本相同,区别在于re.M用于要匹配的字符串内出现换行符,将每个换行符分隔开看做不同的行;而re.X用于匹配的正则表达式内出现的换行符,并且在进行匹配时忽视这些换行符。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值