Python系列01 | 正则表达式

一.基本使用

1.在python中使用正则表达式

在Python中需要通过正则表达式对字符串进⾏匹配的时候,可以使⽤⼀个python处理文本的标准库,标准库的意思是这是一个python内置模块,不需要额外下载,名字为re

re模块的使用:

import re

2.常用元字符

Parameter Description
. 匹配任意1个字符(除了\n)
[] 匹配[ ]中列举的字符
\d 匹配数字,即0-9,等同于[0-9]
\D 匹配非数字,即不是数字
\s 匹配任意的空白符
\S 匹配非任意的空白符
\w 匹配单词字符,即a-z、A-Z、0-9、_
\W 匹配⾮单词字符
^ 匹配字符串的开始
$ 匹配字符串的结束

如果你想匹配没有预定义元字符的字符集合,只需要在方括号里列出它们就行了

e.g.:

# `[0-9]` 等效于`\d`
print(re.match("[0-9]+","10086").group())
print(re.match("\d+","10086").group())
# results: 10086

# 匹配开始与结束,以邮箱为例
print(re.match("^\w+\.\w+@\w+\.\w+$", "Dylan.K@163.com").group())
# results: Dylan.K@163.com

3.字符转义

如果你想查找元字符本身的话,比如你查找.,或者*,就出现了问题:你没办法指定它们,因为它们会被解释成别的意思。这时你就得使用\来取消这些字符的特殊意义。因此,你应该使用\.\*。当然,要查找\本身,你也得用\\.

e.g.:

# 用‘\.’ 来表示‘.’
print(re.findall("Throughput\s*(\d+\.?\d*)\s*MB/s", "Throughput    0.472   MB/s"))
# results: ['0.472']

4.常用的限定符

Parameter Description
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次

e.g.:

# 重复n到m次
print(re.match('[\w]{4,10}@\d{3}.com', 'dylan@163.com').group())
# results: dylan@163.com

5.分组匹配

Parameter Description
| 匹配左右任意⼀个表达式
(ab) 将括号中字符作为⼀个分组
\num 引⽤分组num匹配到的字符串
(?P<name>) 分组起别名,匹配到的子串组在外部是通过定义的 name 来获取的
(?P=name) 引⽤别名为name分组匹配到的字符串

e.g.:

# (163|126|qq) 括号中的表达式作为一个分组
print(re.match('[\w]{4,10}@(163|126|qq).com', 'dylan@163.com').group())
# results: dylan@163.com

二. re.match函数

1.语法介绍

re.match 尝试从字符串的起始位置匹配一个模式,匹配成功 re.match 方法返回一个匹配的对象,否则返回 None。

语法:re.match(pattern, string, flags=0)

Parameter Description
pattern 匹配的正则表达式
string 要匹配的字符串
flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
1.re.I 忽略大小写
2.re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
3.re.M 多行模式
4.re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
5.re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
6.re.X 为了增加可读性,忽略空格和 # 后面的注释

e.g.:

# re.I 忽略大小写
print(re.match('w', 'Www.runoob.com',re.I).group())  
# results: W
# 也可以这么写
print(re.match('[wW]', 'Www.runoob.com',re.I).group()) 
# results: W

# 起始位置匹配不到就会报错
print(re.match('r', 'www.runoob.com').group()) 
# results: None
# 匹配 r 
print(re.match('\w+\.(\w)', 'www.runoob.com').group(1)) 
# results: r

# re.S 用法
print(re.match('.', '.*%',re.S).group()) 
# results: .

2.group()和groups()的使用

我们可以使用group()groups()匹配对象函数来获取匹配后的结果。

2.1 group()

group(...)
    group([group1, ...]) -> str or tuple.
    Return subgroup(s) of the match by indices or names.
    For 0 returns the entire match.

获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回。group1可以使用编号也可以使用别名;编号0代表匹配的整个子串;默认返回group(0);没有截获字符串的组返回None;截获了多次的组返回最后一次截获的子串。

e.g.:

print(re.match("([^.]*)-(\d+)","010-123456789").group())
# results: 010-123456789
print(re.match("([^.]*)-(\d+)","010-123456789").group(1))
# results: 010
print(re.match("([^.]*)-(\d+)","010-123456789").group(2))
# results: 123456789

2.2 groups()

groups(...)
    groups([default=None]) -> tuple.
    Return a tuple containing all the subgroups of the match, from 1.
    The default argument is used for groups
    that did not participate in the match

以元组形式返回全部分组截获的字符串。相当于调用group(1,2,…last)。没有截获字符串的组以默认值None代替。

e.g.:

print(re.match("([^.]*)-(\d+)","010-123456789").groups()) 
# results: ('010', '123456789')

三. re.search函数

re.search 扫描整个字符串并返回第一个成功的匹配,如果没有匹配,就返回一个 None。

re.match与re.search的区别:

re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。

e.g.:

print(re.search("([-])","010-123456789").group())
# results: -            type:str  
print(re.search("([-])","010-123456789").groups()) 
# results: ('-',)      type: tuple

四. re.findall函数

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。

注意: matchsearch 是匹配一次, findall 匹配所有。

e.g.:

# search 匹配一次,返回str
print(re.search("([\.])","www.google.com").group())
# results: .

# findall 匹配所有,返回list
print(re.findall("\.","www.google.com"))
# results: ['.', '.']

五. re.finditer函数

findall 类似,在字符串中找到正则表达式所匹配的所有数据,并把它们作为一个迭代器返回。

print(re.findall("\d+","12ABC32BCD43DEF322"))
# results: ['12', '32', '43', '322']

# finditer 返回迭代器,需要遍历才能获取匹配到的数据
print([i.group() for i in re.finditer("\d+","12ABC32BCD43DEF322")])
# results: ['12', '32', '43', '322']

六. re.sub函数

sub是substitute的所写,表示替换,将匹配到的数据进⾏替换。

1.语法介绍

语法:re.sub(pattern, repl, string, count=0, flags=0)

Parameter Description  
pattern 必选,表示正则中的模式字符串  
repl 必选,就是replacement,要替换的字符串,也可为一个函数  
string 必选,被替换的那个string字符串  
count 可选参数,count 是要替换的最大次数,必须是非负整数。如果省略这个参数或 设为 0,所有的匹配都会被替换
flags 可选参数,标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。  

2.演示

# 替换后四位为0
print(re.sub('\d{4}$','0000','13549876489'))
# results: 13549870000

六. re.split()函数

函数作用:分割字符串,将字符串用给定的正则表达式匹配的字符串进行分割,分割后返回结果list。

1.语法介绍

split(pattern, string, maxsplit=0, flags=0)

Parameter Description
pattern 匹配的正则表达式
string 要匹配的字符串
maxsplit 分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数
flags 可选参数,标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

2.演示

# 根据 : 和 空格进行分割
print(re.split(r":| ","info:xiaoming 22 shanghai"))
# results: ['info', 'xiaoming', '22', 'shanghai']

七. python贪婪和⾮贪婪

Python⾥数量词默认是贪婪的,总是尝试匹配尽可能多的字符;⾮贪婪则相反,总是尝试匹配尽可能少的字符。

注:我们一般使用非贪婪模式来提取。

*,?,+,{m,n}后⾯加上,使贪婪变成⾮贪婪。

# “.+”会从字符串的启始处抓取满⾜模式的最⻓字符
print(re.match(".+(\d+-\d+-\d+)","a number 123-456-789").group(1))
# 3-456-789

#⾮贪婪操作符“?”,要求正则匹配的越少越好
print(re.match(".+?(\d+-\d+-\d+)","a number 123-456-789").group(1))
# 123-456-789

正则表达式模式中使⽤到通配字,那它在从左到右的顺序求值时,会尽量“抓取”满⾜匹配最⻓字符串,.+会从字符串的启始处抓取满⾜模式的最⻓字符,其中包括我们想得到的第⼀个整型字段的中的⼤部分。.+?要求正则匹配的越少越好,