Python编程进阶_04(正则表达式)

re模块的介绍

什么是re模块

在Python中需要通过正则表达式对字符串进行匹配的时候,可以使用一个re模块

re模块使用三步走

1
2
3
4
5
6
# 第一步:导入re模块
import re
# 第二步:使用match方法进行匹配操作
result = re.match(pattern正则表达式, string要匹配的字符串, flags=0)
# 第三步:如果数据匹配成功,使用group方法来提取数据
result.group()

re.match的作用是尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回 none。具体的语法是:

re.match(pattern, string, flags=0)

参数说明:

1.pattern:匹配的正则表达式;

2.string:要匹配的字符串;

3.flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

re.I 使匹配对大小写不敏感
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配,影响^和$
re.S 使.匹配包括换行在内的所有字符
re.U 根据unicode字符集解析字符 这个标志影响\w,\W,\b,\B
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解

re模块的相关方法

re.match(pattern, string, flags=0)

  • 从字符串的起始位置匹配,如果匹配成功则返回匹配内容, 否则返回None

re.findall(pattern, string, flags=0)

  • 扫描整个串,返回所有与pattern匹配的列表
  • 注意: 如果pattern中有分组则返回与分组匹配的列表
  • 举例: re.findall("\d","chuan1zhi2") >> ["1","2"]

re.finditer(pattern, string, flags)

  • 功能与上面findall一样,不过返回的时迭代器

参数说明:

  • pattern : 模式字符串。
  • repl : 替换的字符串,也可为一个函数。
  • string : 要被查找替换的原始字符串。
  • count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
  • flags: 匹配方式:
    • re.I 使匹配对大小写不敏感,
    • re.S 使 . 匹配包括换行在内的所有字符
    • re.M 多行模式,会影响^,$

正则表达式快速入门

案例1:查找一个字符串中是否具有数字“8”

1
2
3
4
5
6
7
import re
result = re.findall('8', '13566128753')
# print(result)
if result:
print(result)
else:
print('未匹配到任何数据')

案例2:查找一个字符串中是否具有数字

1
2
3
4
5
6
7
import re
result = re.findall('\d', 'a1b2c3d4f5')
# print(result)
if result:
print(result)
else:
print('未匹配到任何数据')

案例3:查找一个字符串中是否具有非数字

1
2
3
4
5
6
7
import re
result = re.findall('\D', 'a1b2c3d4f5')
# print(result)
if result:
print(result)
else:
print('未匹配到任何数据')

正则表达式详解

正则编写三步走:查什么、查多少、从哪查

查什么

查什么(匹配符)
查什么,主要是抓住子串的特征,主要依靠匹配符来表示
① : 匹配普通字符:
② : 匹配字符串中的奇数数字:用[]构建范围类 [13579]表示可以从奇数中匹配
③ : 匹配所有数字: [0-9] 在方括号中,可以用中划线-代表一种连续的范围
④ : 匹配偶数:匹配除了奇数以外的就是偶数 ^表示逻辑非
⑤ : 匹配中文: 虽然汉字本身不具有连续性,但是它们在计算机中占据了一块连续的字符编码. \u4e00-\u9fa5
⑥ : 用匹配符,可以十分方便地描述字符串特征:
普通字符:查什么就是什么
如果查询多种字符: []建立范围类 [a-z] [13579]
\d : 查数字 等价于[0-9]
\D: 查非数字 等价于[^0-9]
\w: 单词字符 等价于[a-zA-Z_0-9]
\W: 非单词字符 等价于[^a-zA-Z_0-9]
中文: 中文本身是普通字符 但是为了方便以字符编码构建范围类
[\u4e00-\u9fa5]

查多少

查多少(限定符)
① : 查连续4位数字: 用{}构建量词
查什么:数字 查多少:4位 /\d{4}/
② : 匹配连续的3到6位数字 量词可以表达范围 {N,M}
查什么:数字 查多少:36位 /\d{36}/
③ : 匹配至少4位连续数字 {N,} 至少要N位
查什么:数字 查多少:至少4位
④ : 贪婪模式与非贪婪模式:
系统默认会以量词范围的上限,尽可能长地匹配结果,这种模式成为贪婪模式(饿汉模式)
可以在量词后,加一个?号,切换到非贪婪模式(饱汉模式),尽可能短地匹配结果:
⑤ : 用限定符(量词),可以十分方便地描述要匹配的字符数量:
用{}构建量词,有三种写法 {N} {N,M} {N,}
还有一些方便的量词:
*: 任意个数 等价于:{0,}
+: 至少一个 等价于:{1,}
?: 0个或1个 等价于:{0,1}

从哪查

在哪查(定位符)
① :匹配表单中的手机号码:
查什么:数字 查多少:11位
在正则中,^代表一个字符串开始的位置(最左边的位置)
在正则中,$代表一个字符串结束的位置(最右边的位置)
上述需求非常常见,无论是身份证、手机、邮箱等表单信息,都不允许出现杂质。
/^表单数据$/ 避免杂质的混入
② :匹配一段英文字符串中的单词an
zhangsan have an apple
在英语中,两个单词之间有空格 正则中,有单词边界用 \b 表示。
p1: 查什么:单词边界 查多少:1个 在哪查:任意
p2 : 查什么:an 查多少:1个 在哪查:紧跟p1
p3 : 查什么:单词边界 查多少:1个 在哪查:紧跟p2
/\ban\b/g
③ :匹配zhangsan姓名中的最后一个an
在正则中,有非单词边界用 \B 表示:
p1:查什么:非单词边界 查多少:1个 在哪查:任意位置
p2:查什么:an 查多少:1个 在哪查:紧跟p1
p3:查什么:单词边界 查多少:1个 在哪查:紧跟p2
/\Ban\b/g
④ :需求中与特定位置相关的,一般用定位符来表达:
^ : 字符串最左边(起始标签)
$ : 字符串最右边(结束标签)
\b: 单词边界 单词与空格之间的位置
\B: 非单词边界 字母之间的位置

几个重要概念

子表达式

在正则表达式中,通过一对圆括号括起来的内容,我们就称之为”子表达式”。

1
2
re.search(r'\d(\d)(\d)', 'abcdef123ghijklmn')
注意:Python正则表达式前的 r 表示原生字符串(rawstring),该字符串声明了引号中的内容表示该内容的原始含义,避免了多次转义造成的反斜杠困扰。

正则表达式中ddd中,(\d)(d)就是子表达式,一共有两个()圆括号,则代表两个子表达式

说明:findall方法,如果pattern中有分组则返回与分组匹配的列表,所以分组操作中不适合使用findall方法,建议使用search(匹配一个)或finditer(匹配多个)方法。

捕获

当正则表达式在字符串中匹配到相应的内容后,计算机系统会自动把子表达式所匹配的到内容放入到系统的对应缓存区中(缓存区从$1开始)

image-20210118194614636

案例演示:

1
2
3
4
5
6
7
import re
# 匹配字符串中连续出现的两个相同的单词
str1 = 'abcdef123ghijklmn'
result = re.search(r'\d(\d)(\d)', str1)
print(result.group())
print(result.group(1))
print(result.group(2))

反向引用(后向引用)

在正则表达式中,我们可以通过n(n代表第n个缓存区的编号)来引用缓存区中的内容,我们把这个过程就称之为”反向引用”。

几个练习题

① 查找连续的四个数字,如:3569

答:\d\d\d\d或\d{4}

② 查找连续的相同的四个数字,如:1111
答:(\d)\1\1\1

③ 查找数字,如:1221,3443
答:(\d)(\d)\2\1

④ 查找字符,如:AABB,TTMM(提示:A-Z,正则:[A-Z])
答:([A-Z])\1([A-Z])\2

⑤ 查找连续相同的四个数字或四个字符(提示:w)
答:(\w)\1\1\1

正则表达式其他方法

选择匹配符

可以匹配多个规则

案例:匹配字符串hellojava或hellopython

1
2
3
4
5
6
7
8
import re
str = 'hellojava, hellopython'
result = re.finditer(r'hello(javapython)', str)
if result:
for i in result:
print(i.group())
else:
print('未匹配到任何数据')

分组别名

代码

功能

(?P)

分组起别名

(?P=name)

引用别名为name分组匹配到的字符串

案例:匹配book>

1
2
3
4
import re
str1 = '<book>python</book>'
result = re.search(r'<(?P<mark>(\w+)>)\w+<\/(?P=mark)', str1)
print(result.group())

综合案例

①需求:在列表中[“apple”, “banana”, “orange”, “pear”],匹配apple和pear

1
2
3
4
5
6
7
8
9
import re
list1 = ["apple", "banana", "orange", "pear"]
str1 = str(list1)
result = re.finditer('(applepear)', str1)
if result:
for i in result:
print(i.group())
else:
print('未匹配到任何数据')

②需求:匹配出163、126、qq等邮箱

1
2
3
4
5
6
7
8
import re
email = '1478670@qq.com, go@126.com, heima123@163.com'
result = re.finditer('\w+@(qq126163).com', email)
if result:
for i in result:
print(i.group())
else:
print('未匹配到任何数据')

③需求 : 匹配qq:10567这样的数据,提取出来qq文字和qq号码

1
2
3
4
5
6
7
import re
str1 = 'qq:10567'
result = re.split(r':', str1)
if result:
print(f'{result[0]}号:{result[1]}')
else:
print('未匹配到任何数据')

常用备查

常用1

  • 汉字: ^[\u4e00-\u9fa5]{0,}$
  • 英文和数字:^[A-Za-z0-9]+$^[A-Za-z0-9]{4,40}$
  • 长度为3-20的所有字符:^.{3,20}$
  • 由26个英文字母组成的字符串:^[A-Za-z]+$
  • 由26个大写英文字母组成的字符串:^[A-Z]+$
  • 由26个小写英文字母组成的字符串:^[a-z]+$
  • 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
  • 由数字、26个英文字母或者下划线组成的字符串:^\w+$^\w{3,20}
  • 中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
  • 中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
  • 可以输入含有^%&',;=?$\"等字符:[^%&',;=?$\x22]+
  • 禁止输入含有的字符`[^\x22]+`
  • .*匹配除 \n 以外的任何字符。
  • /[\u4E00-\u9FA5]/ 汉字
  • /[\uFF00-\uFFFF]/ 全角符号
  • /[\u0000-\u00FF]/ 半角符号

常用2

  • Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
  • 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
  • InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
  • 手机号码:^(13[0-9]14[57]15[012356789]18[012356789])\d{8}$
  • 电话号码(“XXX-XXXXXXX”、”XXXX-XXXXXXXX”、”XXX-XXXXXXX”、”XXX-XXXXXXXX”、”XXXXXXX”和”XXXXXXXX):^(\(\d{3,4}-)\d{3.4}-)?\d{7,8}$
  • 国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}\d{4}-\d{7}
  • 身份证号(15位、18位数字):^\d{15}\d{18}$
  • 短身份证号码(数字、字母x结尾):^([0-9]){7,18}(xX)?$ 或 ^\d{8,18}[0-9x]{8,18}[0-9X]{8,18}?$
  • 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
  • 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
  • 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
  • 日期格式:^\d{4}-\d{1,2}-\d{1,2}
  • 一年的12个月(01~09和1~12):^(0?[1-9]1[0-2])$
  • 一个月的31天(01~09和1~31):^((0?[1-9])((12)[0-9])3031)$

常用3

  • xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[xX][mM][lL]$
  • 中文字符的正则表达式:[\u4e00-\u9fa5]
  • 双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
  • 空白行的正则表达式:\n\s*\r (可以用来删除空白行)
  • HTML标记的正则表达式:<(\S*?)[^>]*>.*?</\1><.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
  • 首尾空白字符的正则表达式:^\s*\s*$或(^\s*)(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
  • 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
  • 中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
  • IP地址:\d+\.\d+\.\d+\.\d+ (提取IP地址时有用)
  • IP地址:((?:(?:25[0-5]2[0-4]\\d[01]?\\d?\\d)\\.){3}(?:25[0-5]2[0-4]\\d[01]?\\d?\\d))
  • IP-v4地址:\\b(?:(?:25[0-5]2[0-4][0-9][01]?[0-9][0-9]?)\\.){3}(?:25[0-5]2[0-4][0-9][01]?[0-9][0-9]?)\\b (提取IP地址时有用)
  • 校验IP-v6地址:(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}([0-9a-fA-F]{1,4}:){1,7}:([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6}):((:[0-9a-fA-F]{1,4}){1,7}:)fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5](2[0-4]1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5](2[0-4]1{0,1}[0-9]){0,1}[0-9])([0-9a-fA-F]{1,4}:){1,4}:((25[0-5](2[0-4]1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5](2[0-4]1{0,1}[0-9]){0,1}[0-9]))
  • 子网掩码:((?:(?:25[0-5]2[0-4]\\d[01]?\\d?\\d)\\.){3}(?:25[0-5]2[0-4]\\d[01]?\\d?\\d))
  • 校验日期:^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]1[0-2])-(?:0[1-9]1[0-9]2[0-8])(?:0[13-9]1[0-2])-(?:2930)(?:0[13578]1[02])-31)(?:[0-9]{2}(?:0[48][2468][048][13579][26])(?:0[48][2468][048][13579][26])00)-02-29)$(“yyyy-mm-dd“ 格式的日期校验,已考虑平闰年。)
  • 抽取注释:<!--(.*?)-->
  • 查找CSS属性:^\\s*[a-zA-Z\\-]+\\s*[:]{1}\\s[a-zA-Z0-9\\s.#]+[;]{1}
  • 提取页面超链接:(<a\\s*(?!.*\\brel=)[^>]*)(href="https?:\\/\\/)((? !(?:(?:www\\.)?'.implode('(?:www\\.)?', $follow_list).'))[^" rel="external nofollow" ]+)"((?!.*\\brel=)[^>]*)(?:[^>]*)>
  • 提取网页图片:\\< *[img][^\\\\>]*[src] *= *[\\"\\']{0,1}([^\\"\\'\\ >]*)
  • 提取网页颜色代码:^#([A-Fa-f0-9]{6}[A-Fa-f0-9]{3})$
  • 文件扩展名效验:^([a-zA-Z]\\:\\\\)\\\\([^\\\\]+\\\\)*[^\\/:*?"<>]+\\.txt(l)?$

在线运行正则:https://regex101.com/