Working with Regular Expression in Python.
# 正则表达式
正则表达式是一组由字母和符号组成的特殊文本,它可以用来从文本中找出满足你想要的格式的句子。一个正则表达式是一种从左到右匹配主体字符串的模式,常使用缩写的术语 “regex” 或 “regexp”。
实验网站:regex101
参考:菜鸟
正则语法
元字符
正则表达式起作用主要依赖于元字符的使用。元字符不代表它们本身的字符含义,在正则表达式中他们都用特殊的含义,如果想要表示出它们原有的字符含义就需要使用转义字符。
常用的主要有:
元字符 | 解释 |
---|---|
. | 句号可以匹配任意单个字符,除了换行符 |
[] | 字符种类,匹配一个方括号内描述的任意字符 |
[^] | 否定的字符种类,匹配一个除了方括号内描述的任意字符 |
* | 匹配 >=0 个重复的在*之前的字符或字符种类 |
+ | 匹配 >=1 个重复的在+之前的字符或字符种类 |
? | 匹配?之前的字符为可选(即0个或1个) |
匹配num个在花括号之前的字符或字符集(n <= num <= m) | |
(str) | 字符集,匹配与xyz完全相等的字符串 |
| | 或运算符,可以连接多个字符或字符集 |
\ | 转义符,用于一些保留字符前,可以将保留字符转为可匹配字符 |
^ | 从开始行开始匹配 |
$ | 从末端开始匹配 |
## 点能匹配任意单个字符,但是不能匹配换行符
# .
# .+
## 标识符的正则表达式
# [a-zA-Z_]+[a-zA-Z0-9_]*
## 常量的正则表达式
#
## 量词 +*?{}
简写字符集
正则表达式提供了一些常用字符集的简写,使用方便,但是我们必须记住相应简写的表意
简写 | 解释 |
---|---|
. | 匹配除换行符外的所有字符 |
\w | 匹配所有字母数字一个,等同于 [a-zA-Z0-9_] |
\W | 匹配所有非字母数字一个,即所有的符号,等同于 [^\w] |
\d | 匹配所有数字一个,等同于 [0-9] |
\D | 匹配所有非数字一个,等同于 [^\d] |
\s | 匹配所有空格字符一个,等同于 [\t\n\f\r\p{Z}] |
\S | 匹配所有非空格字符一个,等同于 [^\s] |
\f | 匹配一个换页符 |
\n | 匹配一个换行符 |
\r | 匹配一个回车符 |
\t | 匹配一个制表符 |
\v | 匹配一个垂直制表符 |
\p | 匹配一个CR/LF(等同于\r\n),用于匹配DOS行的终止符 |
注记:大写的简写集是小写的补集
零宽度断言(前后预查)
先行断言和后发断言都属于非捕获簇(不捕获文本 ,也不针对组合计进行计数)。 先行断言用于判断所匹配的格式是否在另一个确定的格式之前,匹配结果不包含该确定格式(仅作为约束)
说人话就是用来做判断的表达式,其本身只是一个条件
断言 | 解释 |
---|---|
?= | 正先行断言-存在 |
?! | 负先行断言-排除 |
?<= | 正后发断言-存在 |
?<! | 负后发断言-排除 |
总的来说,断言用于筛选匹配的结果
- 正先行断言,选出所有主表达式之后跟着?=断言定义的表达式
- 负先行断言,选出所有主表达式之后没有跟随?!断言定义的表达式
- 正后发断言,选出所有主表达式之前的模式是?<=断言定义的表达式
- 负后发断言,选出所有主表达式之前的模式是?<!断言定义的表达式
注: 先行、后发都是指主表达式
## 下正则表达式匹配的模式为单词the/The之后的标识符
# (?<= [T | t]he\s)([a-zA-Z_]+[a-zA-Z0-9_]*)
## 下正则表达式匹配的模式为's之前的表示符
# ([a-zA-Z_]+[a-zA-Z0-9_]*)(?='s)
标志
标志也叫模式修正符,它可以用来修改表达式的搜索结果,这些标志可以任意的组合使用,它也是整个正则表达式的一部分。
标志 | 解释 |
---|---|
i | insensitive 忽略大小写 |
g | global 全局搜索 |
m | multi line 多行修饰符,锚点元字符^ $ 工作范围在每一行的起始位置 |
贪婪匹配和惰性匹配
正则表达式默认使用贪婪匹配,即尽可能长的匹配相关模式。一般是确定了开始和结束的表达式,我们可以用?将贪婪匹配转换为惰性匹配。
e.g. (.at) /
(.?at) 的区别
常用的正则表达式模式
电子邮件
[1]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$
汉字
[2]{0,}$
身份证号
^\d{15}|\d{18}$
标识符
[a-zA-Z_]+[a-zA-Z0-9_]*
re 包
re 模块使 Python 语言拥有全部的正则表达式功能。
compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。
re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。
本章节主要介绍Python中常用的正则表达式处理函数。
re.match()
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match() 就返回 none。
函数语法格式:
re.match(pattern, string, flags=0)
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串 |
flags | 标志位,用于控制正则表达式的匹配方式 |
匹配成功 re.match 方法回返回一个匹配的对象,否则返回None。
import re
print(re.match('www', 'www.runoob.com')) # 在起始位置匹配
print(re.match('com', 'www.runoob.com')) # 不在起始位置匹配
<re.Match object; span=(0, 3), match='www'>
None
我们可以用 group(num=0)
和 groups()
匹配对象函数来获得匹配的表达式。
匹配对象方法 | 描述 |
---|---|
group(num=0) | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。 |
groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。 |
import re
line = "Cats are smarter than dogs"
# ()可以对正则表达式分组并记住匹配的文本
matchObj = re.match(r'(.*) are (.*?) .*', line, re.M | re.I)
if matchObj:
print("matchObj.group() : ", matchObj.group())
print("matchObj.group(1) : ", matchObj.group(1))
print ("matchObj.group(2) : ", matchObj.group(2))
else:
print ("No match!!")
# 匹配的正则表达式中只有两个组,因此如果试图访问第三个组救回报错
matchObj.group() : Cats are smarter than dogs
matchObj.group(1) : Cats
matchObj.group(2) : smarter
re.search()
re.search 扫描整个字符串并返回第一个成功的匹配。
函数语法格式:
re.search(pattern, string, flags=0)
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串 |
flags | 标志位,用于控制正则表达式的匹配方式 |
匹配成功re.search方法返回一个匹配的对象,否则返回None。
import re
print(re.search('www', 'www.runoob.com')) # 在起始位置匹配
print(re.search('com', 'www.runoob.com')) # 不在起始位置匹配
<re.Match object; span=(0, 3), match='www'>
<re.Match object; span=(11, 14), match='com'>
我们可以用 group(num=0)
和 groups()
匹配对象函数来获得匹配的表达式。
匹配对象方法 | 描述 |
---|---|
group(num=0) | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。 |
groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。 |
import re
line = "Cats are smarter than dogs"
# ()可以对正则表达式分组并记住匹配的文本
matchObj = re.search(r'(.*) are (.*?) .*', line, re.M | re.I)
if matchObj:
print("matchObj.group() : ", matchObj.group())
print("matchObj.group(1) : ", matchObj.group(1))
print("matchObj.group(2) : ", matchObj.group(2))
else:
print("No match!!")
matchObj.group() : Cats are smarter than dogs
matchObj.group(1) : Cats
matchObj.group(2) : smarter
re.match() 和 re.search() 的区别
re.match()
只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而 re.search()
匹配整个字符串,直到找到一个匹配,否则返回None。
import re
line = "Cats are smarter than dogs"
matchObj = re.match(r'dogs', line, re.M | re.I)
if matchObj:
print("match --> matchObj.group() : ", matchObj.group())
else:
print("No match!!")
matchObj = re.search(r'dogs', line, re.M | re.I)
if matchObj:
print("search --> searchObj.group() : ", matchObj.group())
else:
print("No match!!")
No match!!
search --> searchObj.group() : dogs
检索和替换
Python 的 re 模块提供了re.sub用于替换字符串中的匹配项。
函数语法:
re.sub(pattern, repl, string, count=0, flags=0)
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
reql | 替换的字符串,也可以是一个函数 |
string | 被查找替换的原始字符串 |
count | 匹配后的最大替换次数,count=0表示全部替换 |
flags | 标志位,用于控制正则表达式的匹配方式 |
import re
phone = "2004-959-559 # 这是一个国外电话号码"
# 删除字符串中的 Python注释
num = re.sub(r'#.*$', "", phone)
print ("电话号码是: ", num)
# 删除非数字(-)的字符串
num = re.sub(r'\D', "", phone)
print ("电话号码是 : ", num)
电话号码是: 2004-959-559
电话号码是 : 2004959559
## reql 是一个函数
import re
# 这个函数的作用是将分组名位value的内容 *2 再转换位字符串的形式输出
def double(matched):
value = int(matched.group('value'))
return str(value * 2)
s = 'A23G4HFD567'
# ?P<name> 用于给分组指定名字
print(re.sub('(?P<value>\d+)', double, s))
A46G8HFD1134
re.complie()
compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。
函数语法格式:
re.compile(pattern[, flags])
-
pattern : 一个字符串形式的正则表达式
-
flags : 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
- re.I 忽略大小写
- re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
- re.M 多行模式
- re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
- re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
- re.X 为了增加可读性,忽略空格和 # 后面的注释
import re
pattern = re.compile(r'\d+') # 用于匹配至少一个数字
m = pattern.match('one12twothree34four') # 查找头部,没有匹配
print(m)
None
re.findall()
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果有多个匹配模式,则返回元组列表,如果没有找到匹配的,则返回空列表。
函数语法格式:
findall(string, pos, endpos)
参数 | 描述 |
---|---|
string | 待匹配的字符串 |
pos | 可选参数,指定字符串的起始位置,默认为0 |
endpos | 可选参数,指定字符串的结束位置,默认为字符串的长度 |
import re
pattern = re.compile(r'\d+') # 查找数字
result1 = pattern.findall('runoob 123 google 456')
result2 = pattern.findall('run88oob123google456', 0, 10)
print(result1)
print(result2)
['123', '456']
['88', '12']
## 匹配多个模式,返回元组列表
import re
result = re.findall(r'(\w+)=(\d+)', 'set width=20 and height=10')
print(result)
[('width', '20'), ('height', '10')]
re.finditer()
和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。
re.finditer(pattern, string, flags=0)
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串 |
flags | 标志位,用于控制正则表达式的匹配方式 |
import re
it = re.finditer(r"\d+", "12a32bc43jf3")
for match in it:
print(match.group())
12
32
43
3
re.split()
split 方法按照能够匹配的子串将字符串分割后返回列表。
re.split(pattern, string, maxsplit=0, flags=0)
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串 |
maxsplit=0 | 最大分割次数,默认为0,表示不限次数 |
flags | 标志位,用于控制正则表达式的匹配方式 |
import re
re.split(' ', 'Hello, world!')
['Hello,', 'world!']