视频加载失败

常用模块之re模块

3197 字
16 分钟
常用模块之re模块

【一】正则语法#

【1】引入#

(1)正则表达式在线测试工具#

  • 一说规则我已经知道你很晕了
  • 首先你要知道的是
    • 谈到正则,就只和字符串相关了。
    • 在我给你提供的工具中,你输入的每一个字都是一个字符串。
  • 其次,如果在一个位置的一个值,不会出现什么变化,那么是不需要规则的。
    • 比如
      • 你要用”1”去匹配”1”
      • 或者用”2”去匹配”2”
      • 直接就可以匹配上。
    • 这连python的字符串操作都可以轻松做到。
    • 那么在之后我们更多要考虑的是在同一个位置上可以出现的字符的范围。

(2)手机号验证案例#

# 京东注册页面获取手机号
有很多校验规则
必须是11位的纯数字 并且必须是常规的手机号开头(13,15,17,18,19)
  • Python代码实现手机号格式验证
'''python实现手机校验功能'''
# 1.获取用户的手机号
phone_num = input('请输入您的手机号 :>>>> ').strip()
# 2.先校验是否是11位
if len(phone_num) == 11:
# 3.再校验是否是纯数字
if phone_num.isdigit():
# 4.校验开头是否合法(随便写几个意思一下)
if phone_num.startswith('13') or phone_num.startswith('15') or phone_num.startswith(
'17') or phone_num.startswith('18'):
print('是一个正常的手机号')
else:
print('手机号开头不合法')
else:
print('手机号必须是纯数字')
else:
print('手机号必须是11位')
  • 正则表达式轻松应对格式匹配
import re
phone_number = input('please input your phone number :>>>> ').strip()
if re.match('^(13|14|15|18)[0-9]{9}$', phone_number):
print('是合法的手机号码')
else:
print('不是合法的手机号码')

【2】字符组#

  • 字符组 :[字符组] 在同一个位置可能出现的各种字符组成了一个字符组
  • 在正则表达式中用[]表示
  • 字符分为很多类
    • 比如数字、字母、标点等等。
  • 假如你现在要求一个位置”只能出现一个数字”
  • 那么这个位置上的字符只能是0、1、2…9这10个数之一。
正则待匹配字符匹配结果说明
[0123456789]8True在一个字符组里枚举合法的所有字符,字符组里的任意一个字符和”待匹配字符”相同都视为可以匹配
[0123456789]aFalse由于字符组中没有”a”字符,所以不能匹配
[0-9]7True也可以用-表示范围,[0-9]就和[0123456789]是一个意思
[a-z]sTrue同样的如果要匹配所有的小写字母,直接用[a-z]就可以表示
[A-Z]BTrue[A-Z]就表示所有的大写字母
[0-9a-fA-F]eTrue可以匹配数字,大小写形式的a~f,用来验证十六进制字符
import re
"""re.findall(正则模式, 文本) 基于正则模式查找所有匹配的文本内容"""
# part1: 通配符->. 字符集-> []
ret1 = re.findall("a", "a,b,c,d,e")
ret1 = re.findall(".", "a,b,c,d,e")
ret1 = re.findall("[ace]", "a,b,c,d,e")
ret1 = re.findall("[a-z]", "a,b,c,d,e")
ret1 = re.findall("[0-9]", "1,2,3,4,5")
ret1 = re.findall("\d", "1,2,3,4,5")
ret1 = re.findall("[0-9a-z]", "1,a,2,b,3")
ret1 = re.findall("[^a-z]", "1,a,2,b,3")
ret1 = re.findall("[^0-9,]", "1,a,2,b,3")
print(ret1)

【3】元字符#

元字符匹配内容
.匹配除换行符以外的任意字符
\w匹配字母或数字或下划线
\s匹配任意的空白符
\d匹配数字
\n匹配一个换行符
\t匹配一个制表符
\b匹配一个单词的结尾
^匹配字符串的开始
$匹配字符串的结尾
\W匹配非字母或数字或下划线
\D匹配非数字
\S匹配非空白符
ab
()匹配括号内的表达式,也表示一个组
[…]匹配字符组中的字符
[^…]匹配除了字符组中字符的所有字符
# part2:重复元字符-> + * {} ?
ret2 = re.findall("[0-9a-zA-Z]", "apple,banana,orange,melon")
ret2 = re.findall("\w", "apple,banana,orange,melon")
ret2 = re.findall("\w+", "apple,banana,orange,melon")
ret2 = re.findall("\w+?", "apple,banana,orange,melon") # 取消贪婪匹配
ret2 = re.findall("\w*", "apple,banana,orange,melon")
ret2 = re.findall("\w{6}", "apple,banana,orange,melon")

【4】量词#

量词用法说明
*重复零次或更多次
+重复一次或更多次
?重复零次或一次
{n}重复n次
{n,}重复n次或更多次
{n,m}重复n到m次

【5】位置元字符**. ^ $**#

正则待匹配字符匹配 结果说明
海.海燕海娇海东海燕海娇海东匹配所有”海.”的字符
^海.海燕海娇海东海燕只从开头匹配”海.”
海.$海燕海娇海东海东只匹配结尾的”海.$”
# part3: 位置元字符-> ^ $
ret3 = re.findall("^\w{5}", "apple,banana,peach,orange,melon")
ret3 = re.findall("\w{5}$", "apple,banana,peach,orange,melon")
ret3 = re.findall("^\w{5}$", "apple,banana,peach,orange,melon")
print(ret3)

【6】重复匹配*** + ? { }**#

正则待匹配字符匹配 结果说明
李.?李杰和李莲英和李二棍子李杰 李莲 李二?表示重复零次或一次,即只匹配”李”后面一个任意字符
李.*李杰和李莲英和李二棍子李杰和李莲英和李二棍子*表示重复零次或多次,即匹配”李”后面0或多个任意字符
李.+李杰和李莲英和李二棍子李杰和李莲英和李二棍子+表示重复一次或多次,即只匹配”李”后面1个或多个任意字符
李.{1,2}李杰和李莲英和李二棍子李杰和 李莲英 李二棍{1,2}匹配1到2次任意字符
  • 注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配

【7】字符集**[][^]**#

正则待匹配字符匹配 结果说明
李[杰莲英二棍子]*李杰和李莲英和李二棍子李杰 李莲英 李二棍子表示匹配”李”字后面[杰莲英二棍子]的字符任意次
李[^和]*李杰和李莲英和李二棍子李杰 李莲英 李二棍子表示匹配一个不是”和”的字符任意次
[\d]456bdha34 5 6 3表示匹配任意一个数字,匹配到4个结果
[\d]+456bdha3456 3表示匹配任意个数字,匹配到2个结果

【8】分组匹配 ()与 或 |[^]#

  • 身份证号码是一个长度为15或18个字符的字符串
    • 如果是15位则全部🈶️数字组成,首位不能为0;
    • 如果是18位,则前17位全部是数字,末位可能是数字或x,
    • 下面我们尝试用正则来表示:
正则待匹配字符匹配 结果说明
^[1-9]\d{13,16}[0-9x]$110101198001017032110101198001017032表示可以匹配一个正确的身份证号
^[1-9]\d{13,16}[0-9x]$11010119800101701101011980010170表示也可以匹配这串数字,但这并不是一个正确的身份证号码,它是一个16位的数字
^[1-9]\d{14}(\d{2}[0-9x])?$1101011980010170False现在不会匹配错误的身份证号了 ()表示分组,将\d{2}[0-9x]分成一组,就可以整体约束他们出现的次数为0-1次
^([1-9]\d{16}[0-9x][1-9]\d{14})$110105199812067023110105199812067023
# part4:
# | 指定原子或正则模式进行二选一或多选一
# () 具备模式捕获的能力,也就是优先提取数据的能力,通过(?:) 可以取消模式捕获
ret4 = re.findall(",\w{5},", ",apple,banana,peach,orange,melon,") # 筛选出5个字符的单词
ret4 = re.findall(",(\w{5}),", ",apple,banana,peach,orange,melon,") # 筛选出5个字符的单词
ret4 = re.findall("\w+@\w+\.com", "123abc@163.com,....234xyz@qq.com,....") # 筛选出5个字符的单词
ret4 = re.findall("(\w+)@qq\.com", "123abc@163.com,....234xyz@qq.com,....") # 筛选出5个字符的单词
ret4 = re.findall("(?:\w+)@(?:qq|163)\.com", "123abc@163.com,....234xyz@qq.com,....") # 筛选出5个字符的单词
print(ret4)

【9】转义符****#

  • 在正则表达式中,有很多有特殊意义的是元字符
    • 比如\n和\s等
    • 如果要在正则中匹配正常的”\n”而不是”换行符”就需要对""进行转义,变成”。
  • 在python中,无论是正则表达式,还是待匹配的内容,都是以字符串的形式出现的,在字符串中\也有特殊的含义,本身还需要转义。
  • 所以如果匹配一次”\n”,字符串中要写成’\n’,那么正则里就要写成”\n”,这样就太麻烦了。
  • 这个时候我们就用到了r’\n’这个概念,此时的正则是r’\n’就可以了。
正则待匹配字符匹配 结果说明
\n\nFalse因为在正则表达式中\是有特殊意义的字符,所以要匹配\n本身,用表达式\n无法匹配
\n\nTrue转义\之后变成\,即可匹配
“\n”‘\n’True如果在python中,字符串中的”也需要转义,所以每一个字符串”又需要转义一次
r’\n’r’\n’True在字符串之前加r,让整个字符串不转义
# part5: 转义符-> \d \D \w \W \n \s \S \b \B
""" \b 1个单词边界原子 """
txt = "my name is nana. nihao,nana"
ret = re.findall(r"na", txt)
ret = re.findall(r"\bna", txt)
ret = re.findall(r"\bna\w{2}", txt)
print(ret) # ['na', 'na', 'na']

【10】贪婪匹配#

  • 贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配
正则待匹配字符匹配 结果说明
<.*> <script>…<script>默认为贪婪匹配模式,会匹配尽量长的字符串
<.*?>r’\d’ 加上?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串
  • 几个常用的非贪婪匹配,Pattern
  • *? 重复任意次,但尽可能少重复
  • +? 重复1次或更多次,但尽可能少重复
  • ?? 重复0次或1次,但尽可能少重复
  • {n,m}? 重复n到m次,但尽可能少重复
  • {n,}? 重复n次以上,但尽可能少重复

(11)

  • . 是任意字符
    • 是取 0 至 无限长度
  • ? 是非贪婪模式。
  • 合在一起就是取尽量少的任意字符,一般不会这么单独写
    • 他大多用在:.*? 就是取前面任意长度的字符,直到一个x出现

【11】模式修正符#

  • 模式修正符,也叫正则修饰符,模式修正符就是给正则模式增强或增加功能的。
值说明
re.I是匹配对大小写不敏感
re.L做本地化识别匹配
re.M多行匹配,影响到^和$
re.S使.匹配包括换行符在内的所有字符
re.U根据Unicode字符集解析字符,影响\w、\W、\b、\B
re.X通过给予我们功能灵活的格式以便更好的理解正则表达式
import re
text = """
<12
>
<x
yz>
<!@#$%>
<1a!#
e2>
<>
"""
result_1 = re.findall("<.*?>", text)
result_2 = re.findall("<.*?>", text, re.S)
print(result_1) # ['<!@#$%>', '<>']
print(result_2) # ['<12\n>', '<x\n yz>', '<!@#$%>', '<1a!#\n e2>', '<>']

【二】正则模块(re)常用方法#

【1】查找结果(findall)#

import re
name_str = "Dream yuan Justin"
# 返回所有满足匹配条件的结果,放在列表里
result = re.findall('a', name_str)
print(result) # 结果 : ['a', 'a']

【2】查找结果(search)#

import re
name_str = "Dream yuan Justin"
# 函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以
# 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
result = re.search('a', name_str).group()
print(result) # 结果 : 'a'

【3】查找结果(match)#

import re
name_str = 'abc'
# 同search,不过尽在字符串开始处进行匹配
result = re.match('a', 'abc').group()
print(result)
# 结果 : 'a'

【4】切割(split)#

import re
name_str = 'abcd'
# 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
result = re.split('[ab]', name_str)
print(result) # ['', '', 'cd']

【5】指定个数替换(sub)#

import re
name_str = 'eva3egon4yuan4'
# 将数字替换成'H',参数1表示只替换1个
result = re.sub('\d', 'H', name_str, 1)
print(result) # evaHegon4yuan4

【6】替换全部(subn)#

import re
name_str = 'eva3egon4yuan4'
# 将数字替换成'H',返回元组(替换的结果,替换了多少次)
result = re.subn('\d', 'H', 'eva3egon4yuan4')
print(result) # ('evaHegonHyuanH', 3)

【7】编译正则表达式(compile)#

import re
# 将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字
obj = re.compile('\d{3}')
# 正则表达式对象调用search,参数为待匹配的字符串
ret = obj.search('abc123eeee')
print(ret.group()) # 结果 : 123

【8】匹配结果为迭代器(finditer)#

import re
# finditer返回一个存放匹配结果的迭代器
ret = re.finditer('\d', 'ds3sy4784a')
print(ret)
# <callable_iterator object at 0x10195f940>
print(next(ret).group())
# 查看第一个结果
print(next(ret).group())
# 查看第二个结果
print([i.group() for i in ret])
# 查看剩余的所有结果

【三】正则方法之优先级#

【1】findall的优先级查询#

import re
ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com')
# 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可
print(ret) # ['oldboy']
ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com')
print(ret) # ['www.oldboy.com']

【2】split的优先级查询#

ret=re.split("\d+","eva3egon4yuan")
print(ret) #结果 : ['eva', 'egon', 'yuan']
ret=re.split("(\d+)","eva3egon4yuan")
print(ret) #结果 : ['eva', '3', 'egon', '4', 'yuan']
  • 在匹配部分加上()之后所切出的结果是不同的,
  • 没有()的没有保留所匹配的项,但是有()的却能够保留了匹配的项,
  • 这个在某些需要保留匹配部分的使用过程是非常重要的。

【四】常用正则表达式#

场景正则表达式
用户名^[a-z0-9_-]{3,16}$
密码^[a-z0-9_-]{6,18}$
手机号码^(?:+86)?1[3-9]\d{9}$
颜色的十六进制值^#?([a-f0-9]
电子邮箱^[a-z\d]+(.[a-z\d]+)*@(\da-z?)+.[a-z]+$
URL^(?:https://
IP 地址((2[0-4]\d
HTML 标签^<([a-z]+)([^<]+)(?:>(.)</\1>
utf-8编码下的汉字范围^[\u2E80-\u9FFF]+$

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

打赏
Profile Image of the Author
Dream
Hello, I'm Dream.
公告
欢迎来到我的博客!爱学习爱进步。
分类
标签
最新动态
站点统计
文章
300
分类
5
标签
26
总字数
640,882
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
Vercel
博客版本
Firefly v6.16.8
文章许可
CC BY-NC-SA 4.0
文章目录