
什么是正则表达式?
正则表达式(Regular Expression),又称规则表达式,通常被用来检索、替换那些符合某个模式(规则)的文本。许多程序设计语言都支持利用正则表达式进行字符串操作。
Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。re 模块使 Python 语言拥有全部的正则表达式功能。
正则表达式的使用对特殊字符进行了转义,所以如果我们要使用原始字符串,只需加一个 r 前缀。
元字符
正则表达式由一些普通字符和一些元字符(metacharacters)组成。普通字符包括大小写的字母和数字,而元字符则具有特殊的含义。下列为一些常见的元字符的使用说明。
匹配边界:
^ 匹配行首
$ 匹配行尾
重复次数:
? 重复匹配0次或1次
* 重复匹配0次或更多次
+ 重复匹配1次或更多次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n~m次
各种字符的表示:
. 匹配除了换行符以外的任意字符串
[a-z] 任意a-z的字母
[abc] a,b,c中任意字符
\d 匹配数字
\D 匹配任意非数字的字符
\w 数字,字母,下划线
\W 匹配任意不是字母,数字,下划线的字符
\s 空白字符(回车,制表,空格)
\S 匹配任意不是空白符的字符
\b 单词的边界
\B 匹配不是单词开始和结束的位置
其他:
[^123abc] 匹配除了123abc这几个字符以外的任意字符
123|abc 匹配123或者abc
Pattern 对象
compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 re 模块的查找方法使用。语法格式为:
pattern = re.compile(r'正则表达式','匹配模式')
# 常用的匹配模式:
# re.S 可以让 . 匹配换行符
# re.I 忽略大小写
# re.M 多行匹配,影响 ^ 和 $
单次匹配
re 模块中,有两个方法,match 函数和 search 函数,这两个函数都是单次匹配,都返回一个
Match 对象。
re.match(pattern, string, start, end)
# pattern.match(string, start, end)
re.search(pattern, string, start, end)
# pattern.match(string, start, end)
# pattern 正则表达式对象
# string 要匹配的目标字符串
# start 要匹配的目标字符串的起始位置(可选)
# end为 要匹配的目标字符串的结束位置(可选)
"""案例"""
import re
pattern = re.compile(r'\w+', re.I)
string = 'I love python'
result = pattern.match(string, 2, 6)
print(result)
# <re.Match object; span=(2, 6), match='love'>
print(result.group())
# love
需要注意的是,match 函数 只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None,而 search 函数是匹配整个字符串,直到找到一个匹配。
import re
string = 'i am 18 !!!'
result1 = re.match(r'\d+', string)
result2 = re.search(r'\d+', string)
print(result1)
# None
print(result2.group())
# 18
分组
在Python中,正则表达式分组就是用一对圆括号“()”括起来的正则表达式,匹配出的内容就表示一个分组。即每个圆括号都是一个分组,从1开始。需要注意的是,有一个隐含的全局分组(就是0),也就是整个正则表达式。
import re
pattern = re.compile(r'name is (.*),age:(\d+)', re.I)
string = 'my name is 啊哈哈君,age:18 !'
result = pattern.search(string)
print(result)
# <re.Match object; span=(3, 22), match='name is 啊哈哈君,age:18'>
print(result.group())
# name is 啊哈哈君,age:18
print(result.group(1))
# 啊哈哈君
print(result.group(2))
# 18
Match 对象
关于match函数和search函数返回的match对象,也是有很多方法可以调用的。如上述案例的group函数,会返回被匹配的字符串。
# 返回被匹配的字符串,等价于group(0)
Match.group()
# 返回第n个分组匹配的字符串,如果组号不存在,则返回indexError异常
Match.group(n)
# 返回组号为n到m组所匹配的字符串的元组,如果组号不存在,则返回indexError异常
Match.group(n,m)
# 返回所有分组匹配的字符串的元组
Match.groups()
# 返回匹配开始的位置
Match.start()
# 返回匹配结束的位置
Match.end()
# 返回一个元组包含匹配 (开始,结束) 的位置
Match.span()
多次匹配
re 模块中的findall函数与finditer函数用于进行多次匹配。相信通过函数名,有些小伙伴就可以知道这两个函数的返回值。
import re
string = 'abcdefg'
result1 = re.findall(r'\w', string)
result2 = re.finditer(r'\w', string)
print(result1)
# ['a', 'b', 'c', 'd', 'e', 'f', 'g']
print(result2)
# <callable_iterator object at 0x000002452F017848>
由上述案例可看出,多次匹配与单次匹配的函数用法相同,也可以加start和end。只是findall函数返回的是一个列表,而finditer返回的是一个迭代器。
分割字符串
re 模块提供了一个spilt函数,用于通过正则表达式分割字符串,并返回一个列表。
import re
pattern = re.compile(r'\s', re.I)
string = 'python java c++'
result = pattern.split(string)
print(result)
# ['python', 'java', 'c++']
替换字符串
re 模块中的sub函数用于通过正则表达式替换字符串。格式为:
re.sub(pattern, repl, string, count)
# pattern.sub(repl, string, count)
# pattern 正则表达式或者正则对象
# repl 替换的字符串,也可为一个函数
# string 要被查找替换的原始字符串
# count 匹配后替换的最大次数,默认为0,表示替换所有的匹配
这个函数通过案例是很容易理解的。
import re
pattern = re.compile(r'python', re.I)
string = 'I Love Python, Python NB!'
result1 = pattern.sub('java', string)
result2 = pattern.sub('java', string, 1)
print(result1)
# I Love java, java NB!
print(result2)
# I Love java, Python NB!
当repl为函数时,函数的参数只能为match对象,并且这个函数必须有返回值,返回值的格式是字符串,将来就用这个字符串作为替换的内容。
import re
pattern = re.compile(r'python', re.I)
def func(matched):
return matched.group()+' And Java'
string = 'I Love Python'
result = pattern.sub(func, string)
print(result)
# I Love Python And Java
贪婪模式与非贪婪模式
贪婪匹配:正则表达式一般趋向于最大长度匹配,也就是所谓的贪婪匹配。
非贪婪匹配:就是匹配到结果就好,取最少的匹配字符。
在Python中,默认是贪婪模式,而在正则表达式的量词后面直接加上一个问号?就会转换为非贪婪模式。
import re
string = 'i am 18 !'
result1 = re.search(r'\d+', string)
result2 = re.search(r'\d+?', string)
print(result1.group())
# 18
print(result2.group())
# 1
在上述案例中的正则为\d+,也就是匹配数字1次或多次。也就是说,在贪婪模式下,这个正则会往多的次数匹配,也就是优先多次,即匹配到了18,而非贪婪模式下,则会优先匹配1次,也就是优先匹配到了1,满足条件便会立刻返回结果。