正则表达式
- 基本的元字符
- . 表示任意字符(除了换行符:\n)
- []用来匹配一个指定的字符类别(字符集),对于字符集中的字符可以理解成或的关系。比如[a-zA-Z0-9]能够匹配任意大小写字母和数字
- ^ 如果放在字符串的开头,则表示取非的意思。[^5]表示除了5之外的其他字符。而如果^不在字符串的开头,则表示它本身。
- 具有重复功能的元字符:
- 对于前一个字符重复0到无穷次
- 对于前一个字符重复1到无穷次
- ? 对于前一个字符重复0到1次
- {m,n} 对于前一个字符重复次数在为m到n次,其中,{0,} = *,{1,} = , {0,1} = ?
- {m} 对于前一个字符重复m次
- 其它类型:
- \d 匹配任何十进制数;等价于 [0-9]
- \D 匹配任何非数字字符;等价于 [^0-9]
- \s 匹配任何空白字符;等价于 [ \f\n\r\t\v]
- \S 匹配任何非空白字符;等价于 [^ \f\n\r\t\v]
- \w 匹配包括下划线的任何单词字符。等价于[A-Za-z0-9_]
- \W 匹配任何非单词字符。等价于 [^A-Za-z0-9_]
- 字符串的开始和结尾:字符串开始用^(脱字符)匹配,字符串结尾用$(美元符号)匹配
re模块介绍
re模块提供的类
re模块提供最重要的2个类
类 | 描述 |
---|---|
Regular Expression Objects | 正则表达式对象,用于执行正则表达式相关操作的实体 |
Match Objects | 正则表达式匹配对象,存放正则表达式匹配结果并提供获取相关匹配结果的方法 |
- Regular Expression Objects
通过re模块的 compile()函数编译得到的正则表达式对象:regex = re.compile([a-z])
match(string[, pos[, endpos]])
- pos 表示从string字符串的哪个位置开始,相当于先对字符串做切片处理
- endpos 表示到string字符串的哪个位置结束(不包含该位置)如果endpos小于pos,则不会找到任何匹配
- maxsplit 表示最大切割次数;默认值为0,表示能切割多少次就尽可能多的切割多少次
- count regex.sub()和regex.subn()方法的可选参数,表示最大替换次数;默认为0,表示能替换多少次就尽可能多的替换多少次 | regex.match | 在string开始位置匹配正则表达式,如果0或更多字符被匹配则返回对应的对象,否则返回None | | —- | —- | | regex.fullmatch | 全匹配,正则表达式前后加上边界元字符’^’和’$’ | | regex.search | 查找正则表达式可以匹配的子串第一次出现的位置,并返回相应的匹配对象 | | regex.findall | 搜索字符串中与正则表达式匹配的所有子串,以列表形式返回 | | regex.finditer | 搜索字符串中与正则表达式匹配的所有子串,以迭代器形式返回 | | regex.sub | 替换字符串中与正则表达式匹配的count个子串,返回替换修改后的字符串 | | regex.subn | 同sub,还会返回替换次数 | | regex.split | 以正则表达式匹配的字符串为分隔符,对一个字符串进行分隔,以列表形式返回各个子串 | | regex.pattern | | | regex.flags | | | regex.groups | 表达当前正则表达式对象中指定的”捕获组”的数量 | | regex.groupindex | 返回字典对象,{命名分组的分组名:分组数量} |
- Match Objects
调用正则表达式对象的regex.match()、regex.fullmatch()和regex.search()得到的结果就是一个匹配对象,匹配对象支持以下方法和属性
- group m.group()、m.start()、m.end()和m.span()方法中的group参数都表示要选择的分组索引值,1表示第一个分组,2表示第二个分组,依次类推,group参数的默认值是0,表示整个正则表达式所匹配的内容
- default m.groups()与m.groupdict()方法中的default都是为未匹配成功的捕获组提供默认匹配值的。 | match.expend | 通过匹配对象来构造并返回一个新的字符串 | | —- | —- | | match.group | 返回值是包含每一个指定分组所对应的匹配字符串的元组 | | match.groups | 返回一个包含所有分组所匹配内容的元组 | | match.groupdict | | | match.start | 返回指定分组所匹配到的子串切片的开始位置 | | match.end | 返回指定分组所匹配到的子串切片的结束位置 | | match.span | (m.start(group),m.end(group)) | | match.re | | | match.string | | | match.pos | | | match.endpos | | | match.lastindex | | | match.lastgroup | |
re模块提供的函数
函数名 | 描述 |
---|---|
re.match | re.match(pattern,string,flags=0) |
re.fullmatch | |
re.search | |
re.findall | |
re.finditer | |
re.sub | |
re.subn | |
re.split | |
re.compile | |
re.purge | |
re.escape |
标志位(flags)
- 说明:这些flag可以单独使用,也可以通过逻辑或操作符’|’进行拼接来联合使用 | re.A | 匹配ASCII码形式,而非匹配Unicode形式 | | —- | —- | | re.U | 默认值,不使用 | | re.I | 忽略字符大小写 | | re.M | 多行匹配 | | re.L | 使\w \W \b \B的匹配依赖当前环境 | | re.S | 影响’.’,使’.’可以匹配换行符 | | re.X | 忽略空白字符和注释 |
应用
匹配 ```python import re def display_match_obj(match_obj): if match_obj is None:
print('Regex Match Fail!')
else:
print('Regex Match Success!', match_obj)
if name==’main‘: p = re.compile(r’[a-z]+’) display_match_obj(p.match(‘hello’)) display_match_obj(p.match(‘hello123’)) display_match_obj(p.fullmatch(‘hello’)) display_match_obj(p.fullmatch(‘hello123’))
display_match_obj(p.match(‘123hello’)) display_match_obj(p.match(‘123hello’, 3)
Regex Match Success! <_sre.SRE_Match object; span=(0, 5), match='hello'> Regex Match Success! <_sre.SRE_Match object; span=(0, 5), match='hello'> Regex Match Success! <_sre.SRE_Match object; span=(0, 5), match='hello'> Regex Match Fail! Regex Match Fail! Regex Match Success! <_sre.SRE_Match object; span=(3, 8), match='hello'>
2. 查找
```python
import re
string = 'abcdef'
print(re.match(r'c', string)) #None
print(re.search(r'c', string)) #<_sre.SRE_Match object; span=(2, 3), match='c'>
text = "He was carefully disguised but captured quickly by police."
for m in re.finditer(r"\w+ly", text):
print("%02d-%02d: %s" % (m.start(), m.end(), m.group())) #07-16: carefully 40-47: quickly
print(re.findall(r"\w+ly", text)) #['carefully', 'quickly']
- 替换 ```python import re
text = ‘pro——gram-files’ print(re.sub(r’-+’, ‘’, text)) #programfiles print(re.subn(r’-+’, ‘’, text)) #(‘programfiles’, 2) 返回替换次数
4. 分隔
```python
import re
print(re.split(r'\W+', 'Words, words, words.')) #['Words', 'words', 'words', '']
print(re.split(r'\W+', 'Words, words, words.', 1)) #['Words', 'words, words.']
print(re.split(r'[a-f]+', '0a3B9', flags=re.IGNORECASE)) #['0', '3', '9']
匹配对象的说明
当我们通过re.match或re.search函数得到一个匹配对象m后,可以通过if m is None来判断是否匹配成功。在匹配成功的条件下,我们可能还想要获取匹配的值。Python中的匹配对象主要是以“组”的形式来获取匹配内容的
import re
p = re.compile(r'.*name\s+is\s+(\w+).*am\s+(?P<age>\d{1,3})\s+years.*tel\s+is\s+(?P<tel>\d{11}).*', re.S)
string = '''
My name is Tom,
I am 16 years old,
My tel is 13972773480.
'''
m = re.match(p, string)
# 或
# m = p.match(string)
if m is None:
print('Regex match fail.')
else:
result = '''
name: %s
age: %s
tel: %s
'''
print(result % (m.group(1), m.group(2), m.group('tel')))
'''
name: Tom
age: 16
tel: 13972773480
'''
- 由于要匹配的字符串中包括换行符,为了让元字符’.’能够匹配换行符,所以编译正则表达式需要指定re.DOTALL这个flag
- 调用匹配对象的方法或属性前需要判断匹配是否成功,如果匹配失败,得到的匹配对象将是None,其方法和属性调用会报错
- 对于”非命名捕获组”只能通过分组索引数字来获取其匹配到的内容,如m.group(1);而对于命名捕获组既可以通过分组索引数字来获取其匹配到的内容,如m.group(2),也可以通过分组名称来获取其匹配到的内容,如m.group(‘tel’)
输出如下: ```python match_obj.group(): 匹配到的所有内容:print('match_obj.group(): ', '匹配到的所有内容: ', m.group())
print('match_obj.group(0): ', '同上: ', m.group(0))
print('match_obj.group(1): ', '第一个捕获组匹配到的内容: ', m.group(1))
print('match_obj.group(2): ', '第二个命名捕获组匹配到的内容: ', m.group(2))
print('match_obj.group("tel"): ', '第三个命名捕获组匹配到的内容: ', m.group('tel'))
print('match_obj.groups(): ', '所有捕获组匹配到的内容组成的元组对象: ', m.groups())
print('match_obj.groupdict(): ', '所有命名捕获组匹配到的内容组成的字典对象: ', m.groupdict())
print('match_obj: ', '直接打印匹配对象: ', m)
print('match_obj.string: ', '传递给re.match函数的字符串参数: ', m.string)
print('match_obj.re: ', '传递给re.match函数的正则表达式对象: ', m.re)
print('match_obj.pos, match_obj.endpos: ', '传递个match方法的pos和endpos参数: ', m.pos, m.endpos)
print('match_obj.pos, match_obj.start(1), match_obj.end(1): ', '第一个捕获组匹配的内容在字符串中的切片位置: ', m.start(1), m.end(1))
print('match_obj.pos, match_obj.span(1): ', '第一个捕获组匹配的内容在字符串中的切片位置: ', m.span(1))
print('match_obj.pos, match_obj.start("tel"), match_obj.end("tel"): ', '命名捕获组tel匹配的内容在字符串中的切片位置: ', m.start('tel'), m.end('tel'))
print('match_obj.pos, match_obj.span(tel): ', '命名捕获组tel匹配的内容在字符串中的切片位置: ', m.span('tel'))
My name is Tom, I am 16 years old, My tel is 13972773480.
match_obj.group(0): 同上:
My name is Tom,
I am 16 years old,
My tel is 13972773480.
match_obj.group(1): 第一个捕获组匹配到的内容: Tom
match_obj.group(2): 第二个命名捕获组匹配到的内容: 16
match_obj.group(“tel”): 第三个命名捕获组匹配到的内容: 13972773480
match_obj.groups(): 所有捕获组匹配到的内容组成的元组对象: (‘Tom’, ‘16’, ‘13972773480’)
match_obj.groupdict(): 所有命名捕获组匹配到的内容组成的字典对象: {‘age’: ‘16’, ‘tel’: ‘13972773480’}
match_obj: 直接打印匹配对象: <_sre.SRE_Match object; span=(0, 75), match='\n My name is Tom,\n I am 16 years old,\n >
match_obj.string: 传递给re.match函数的字符串参数:
My name is Tom,
I am 16 years old,
My tel is 13972773480.
match_obj.re: 传递给re.match函数的正则表达式对象: re.compile('.*name\\s+is\\s+(\\w+).*am\\s+(?P
正则表达式的前缀
你只需要在表示正则表达式的字符串前加上一个前缀r就可以把这个字符串当然正则表达式来写了。 r是Raw,即“原始”的意思,带有r前缀的字符串就叫做“Raw String”,即原始字符串的意思。也就是说当一个字符串带有r前缀时,它的字面值就是其真实值,也就是正则表达式的值。
- 解决’反斜线瘟疫’
简单来说,表示正则表达式匹配规则的字符串前面的r前缀是为了解决字符串中的反斜线与正则表达式中的反斜线引起的冲突问题。另外,我们根本无需关心哪些字符会引起这样的冲突,只需要在每个表示正则表达式的字符串前加上一个r前缀就可以了