正则表达式
正则表达式,regular expression,通常被简写为 regex,其作用是对于信息的提取。
- 基本用法
- 常见元字符及语法
- 使用正则表达式编程
- 练习题
- 优质学习资源推荐
基本用法
python 中的正则表达式使用不需要安装第三方库,只需要调用re
库即可,具体写法为:
import re
subject = "我是一个粉刷匠,粉刷本领强。"
reobj = re.compile(r'.*(粉刷匠).*')
matchobj = reobj.match(subject)
if matchobj:
print(matchobj.group(1))
# 输出结果
# 粉刷匠
这是一个简单的语句,大家暂时只需要了解就行了。下面将结合例子,讲解正则表达式的内容。
常见元字符及语法
元字符用法说明
12大元字符包括:^ $ . * ? + { [ | ( ) \
。 注意:不包括 ] - }
这是因为:12大元字符(metacharacters)需要转义字符 /
进行声明,而 ]
和 -
只有在位于一个没有转义的 [
之后才是元字符,}
不需要转义。
# -*- coding:utf-8 -*-
import re
"""
^: 匹配字符开头
$: 匹配字符结尾
.: 匹配除换行符(\n)之外的任意字符
*: 匹配字符次数(>=0)
?: 非贪婪匹配
+: 匹配字符次数(>=1)
{}: 用来指定匹配次数
[]: 用来表示字符集
|: 表示逻辑"或"
\: 转义字符
"""
## Task1: ^ $ . * 的用法
subject_1 = "woww"
reobj_1_1 = re.compile(r"^w.*w$")
# 匹配以w开头, w结尾的字符串, 中间可以为任意长度字符
print(reobj_1_1.match(subject_1).group())
# 匹配结果为:woww
## Task2: ?的用法, 关于贪婪匹配和非贪婪匹配
subject_2 = "hahawoooooooooooww"
reobj_2_1 = re.compile(r".*(w.*w).*")
print(reobj_2_1.match(subject_2).group(1))
# 匹配结果为: ww
# 原因: 贪婪匹配时, 前面的 hahawooooooooooo 全部视作 .*
# 此时的执行顺序可以视为从字符串右边开始
reobj_2_2 = re.compile(r".*?(w.*?w).*")
print(reobj_2_2.match(subject_2).group(1))
# 匹配结果为: wooooooooooow
# 原因: 非贪婪匹配时, 执行顺序从左往右
# ?(w.*?w)的实质为第一个"w....w"形式的字符串
## Task3: {} [] 的用法
# 简单手机号码匹配
# 手机号码特征:长度为11位;
# 常用号段(简单起见, 以前两位为例): 13、15、17、18
subject_3_1 = "12332539403" # 非手机号码
subject_3_2 = "13902899430" # 正常手机号码
reobj_3 = re.compile(r"1[3 5 7 8][0-9]{9}")
# 以1开头, 第二位是3 5 7 8, 后面为0-9且共9位
if not reobj_3.match(subject_3_1) and reobj_3.match(subject_3_2):
print("yes")
# 输出结果: yes
## Task4: () | 的用法
# 判断性别是否正确录入
# 性别只能为"男"或"女"
subject_4_1 = "性别 女"
subject_4_2 = "性别 难"
reobj_4 = re.compile(r"(性别 )(男|女)")
# ()进行分组, | 表示男或女
if reobj_4.match(subject_4_1) and not reobj_4.match(subject_4_2):
print("yes")
# 输出结果: yes
预定义字符集用法说明
写法 | 含义 |
---|---|
\d | 数字 [0-9] |
\D | 非数字 |
\s | 空白字符 [\t \r \n \f \v] |
\S | 非空白字符 |
\w | 单词字符 [0-9] [a-z] [A-Z] _(下划线) |
\W | 非单词字符 |
[\u4E00-\u9FA5] | 汉字 |
关于转义字符的一些解释
转义字符 \ 的意义在于,将元字符进行翻译,这里的元字符是指12大元字符。
为了避免操作时出现的混乱,Python 为我们提供了一种简便的写法,即 r""
。在该语句中,所有元字符都不需要使用 \ 来说明其意义。
匹配不可打印字符
名称 | 指令 | 16进制 |
---|---|---|
响铃(bell) | \a | 0X07 |
退出(escape) | \e | 0X1B |
换页(form feed) | \f | 0X0C |
换行(line feed) | \n | 0X0A |
回车(carriage return) | \r | 0X0D |
水平制表符(horizontal tab) | \t | 0x09 |
垂直制表符(vertical tab) | \v | 0x0B |
在正则表达式中添加注释
用来解释说明正则表达式含义。方法很简单,只需要在前面添加(?#...)
即可,具体用法如下:
re.compile(r"(?#姓名)(\w+)")
使用正则表达式编程
创建正则表达式对象
re.compile(r".*\d+")
检测是否可以在目标字符串中找到匹配
if re.search("regex pattern", subject):
# successful match
else:
# match attempt failed
检测正则表达式能否匹配整个目标字符串
if re.match(r"regex pattern\Z", subject):
# \Z 表示定位结束符,定位在末尾,作用同 $
# successful match
else:
# match attempt failed
获取匹配文本
matchobj = re.search(r"regex pattern", subject)
if matchobj:
result = matchobj.group()
else:
result = ""
确定匹配的位置和长度
matchobj = re.search(r"\d+", subject)
if matchobj:
matchstart = matchobj.start()
matchlength = matchobj.end() - matchstart()
命名捕获
matchobj = re.search("http://([a-z0-9.-]+)", subject)
if matchobj:
result = matchobj.group(1)
Python 支持最多 99 个 group
分组,分组标号从 0 开始。
其中,group(0)
表示整个正则表达式的匹配。
如果想获取包含所有分组所匹配文本的一个元组,调用 groups()
方法。
如果想获取包含所有分组所匹配文本的一个字典,调用 groupdict()
方法。
获取所有匹配的列表
result = re.findall(r"\d+", subject)
遍历全部匹配
for matchobj in re.finditer(r"\d+", subject):
......
拆分字符串
result = re.split("<[^<>]*>", subject)
逐行查找
lines = re.split("\r?\n", subject)
reobj = re.compile("regex pattern")
for line in lines[:]:
if re.search(line):
# The regex matches line
else:
# The regex does not match line
替换掉匹配字符
result = re.sub("before", "after", subject)
练习题
这里给大家出几个练习题,正好巩固一下所学知识。
E-Mail地址合法性验证
要求:
以 @ 符号划分,其中 @ 符号之前的为用户名,@ 符号之后的为域名。
用户名和域名均为常用字符,可以包含一个或多个点号,但是不允许出现两个连续的点号。
另外,用户名和域名的第一个和最后一个字符不允许为点号。
传统日期合法性验证
要求: 日期格式为 mm/dd/yy、mm/dd/yyyy、dd/mm/yy 和 dd/mm/yyyy。
传统时间格式的合法性验证
要求: 时间格式为 hh:mm 和 hh:mm:ss,并且要包括 12 小时制和 24 小时制。
优质学习资源推荐
- 博客:正则表达式指南。可以作为 cookbook 进行快速查阅,缺点是 python 版本为 2.4。
- 知乎:你是如何学会正则表达式的?。内容非常丰富,推荐推荐!
- 博客:《构造正则表达式引擎》。建议有一定基础的人再去学习,我暂时只是收藏。
- 书籍:《正则表达式经典实例》。本书汇集了 8 种语言的正则表达式内容,非常全面。