100天精通Python—第34天:正则表达式大总结

Posted 小袁ITSuper

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了100天精通Python—第34天:正则表达式大总结相关的知识,希望对你有一定的参考价值。

文章目录

每篇前言

  • 🏆🏆作者介绍:Python领域优质创作者、华为云享专家、阿里云专家博主、2021年CSDN博客新星Top6

  • 🔥🔥本文已收录于Python全栈系列专栏《100天精通Python从入门到就业》
  • 📝​📝​此专栏文章是专门针对Python零基础小白所准备的一套完整教学,从0到100的不断进阶深入的学习,各知识点环环相扣
  • 🎉🎉订阅专栏后续可以阅读Python从入门到就业100篇文章还可私聊进两百人Python全栈交流群(手把手教学,问题解答); 进群可领取80GPython全栈教程视频 + 300本计算机书籍:基础、Web、爬虫、数据分析、可视化、机器学习、深度学习、人工智能、算法、面试题等。
  • 🚀🚀加入我一起学习进步,一个人可以走的很快,一群人才能走的更远!


一、正则表达式概述

正则表达式是一个强大的字符串处理工具,几乎所有的字符串操作都可以通过正则表达式来完成,其本质是一个特殊的字符序列,可以方便的检查一个字符串是否与我们定义的字符序列的某种模式相匹配。

在Python中经常会用在:爬虫爬取数据时、数据开发、文本检索和数据筛选的时候常用正则来检索字符串等等,正则表达式已经内嵌在Python中,通过import re模块就可以使用。作为刚学Python的新手大多数都听说“正则”这个术语,本文将详细讲解从正则表达式的基础到Python中正则表达式所有语法,保证所有小白从入门到精通!!!

1、语法大全

由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'\\t',等价于 \\\\t )匹配相应的特殊字符。

下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。

模式描述
^匹配字符串的开头
$匹配字符串的末尾。
.匹配除 “\\n” 之外的任何单个字符。要匹配包括 ‘\\n’ 在内的任何字符,请使用象 ‘[.\\n]’ 的模式。
[...]用来表示一组字符,单独列出:[amk] 匹配 ‘a’,‘m’或’k’
[^...]不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。
re*匹配0个或多个的表达式。
re+匹配1个或多个的表达式。
re?匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式
ren匹配n个前面表达式。例如,"o2“不能匹配"Bob"中的"o”,但是能匹配"food"中的两个o。
re n,精确匹配n个前面表达式。例如,"o2,“不能匹配"Bob"中的"o”,但能匹配"foooood"中的所有o。"o1,“等价于"o+”。"o0,“则等价于"o*”。
re n, m匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式
a| b匹配a或b
(re)匹配括号内的表达式,也表示一个组
(?imx)正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。
(?-imx)正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。
(?: re)类似 (…), 但是不表示一个组
(?imx: re)在括号中使用i, m, 或 x 可选标志
(?-imx: re)在括号中不使用i, m, 或 x 可选标志
(?#...)注释.
(?= re)前向肯定界定符。如果所含正则表达式,以 … 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。
(?! re)前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功。
(?> re)匹配的独立模式,省去回溯。
\\w匹配包括下划线的任何单词字符。等价于’[A-Za-z0-9_]’。
\\W匹配任何非单词字符。等价于 ‘[^A-Za-z0-9_]’。
\\s匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \\f\\n\\r\\t\\v]。
\\S匹配任何非空白字符。等价于 [^ \\f\\n\\r\\t\\v]。
\\d匹配任意数字,等价于 [0-9]。
\\D匹配一个非数字字符。等价于 [^0-9]。
\\A匹配字符串开始
\\Z匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。
\\z匹配字符串结束
\\G匹配最后匹配完成的位置。
\\b匹配一个单词边界,也就是指单词和空格间的位置。例如, ‘er\\b’ 可以匹配"never" 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。
\\B匹配非单词边界。‘er\\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。
\\n, \\t, 等。匹配一个换行符。匹配一个制表符, 等
\\1...\\9匹配第n个分组的内容。
\\10匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。

PS:上表中re代表自己写的某一个具体匹配模式

2、修饰符 - 可选标志

正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:

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

3、运算符优先级

正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似。

相同优先级的从左到右进行运算,不同优先级的运算先高后低。下表从最高到最低说明了各种正则表达式运算符的优先级顺序:

运算符描述
\\转义符
(), (?:), (?=), []圆括号和方括号
*, +, ?, n, n,, n,m限定符
^, $, \\任何元字符、任何字符定位点和序列(即:位置和顺序)
|替换,“或"操作字符具有高于替换运算符的优先级,使得”m|food“匹配"m"或"food”。若要匹配"mood"或"food",请使用括号创建子表达式,从而产生"(m|f)ood"。

4、实例简单字符匹配

实例描述
[Pp]ython匹配 “Python” 或 “python”
rub[ye]匹配 “ruby” 或 “rube”
[aeiou]匹配中括号内的任意一个字母
[0-9]匹配任何数字。类似于 [0123456789]
[a-z]匹配任何小写字母
[A-Z]匹配任何大写字母
[a-zA-Z0-9]匹配任何字母及数字
[^aeiou]除了aeiou字母以外的所有字符
[^0-9]匹配除了数字外的字符

二、re 模块

1、re模块操作

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

1. re模块的使用过程

# 导入re模块
import re

# 使用match方法进行匹配操作
result = re.match(正则表达式,要匹配的字符串)

# 如果上一步匹配到数据的话,可以使用group方法来提取数据
result.group()

2. 示例(匹配以itcast开头的语句)


>>> import re

>>> result = re.match("itcast","itcast.cn")
>>> result.group()
'itcast'

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

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

参数说明

  • pattern: 匹配的正则表达式
  • string: 要匹配的字符串。
  • flags: 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

2、匹配单个字符

在上一小节中,了解到通过re模块能够完成使用正则表达式来匹配字符串

本小节,将要讲解正则表达式的单字符匹配

字符功能
.匹配任意1个字符(除了\\n)
[ ]匹配[ ]中列举的字符
\\d匹配数字,即0-9
\\D匹配非数字,即不是数字
\\s匹配空白,即 空格,tab键
\\S匹配非空白
\\w匹配单词字符,即a-z、A-Z、0-9、_
\\W匹配非单词字符

示例1.的用法

>>> import re

>>> ret = re.match(".","M")
>>> print(ret.group())
M

>>> ret = re.match("t.o","too")
>>> print(ret.group())
too

>>> ret = re.match("t.o","two")
>>> print(ret.group())
two

示例2:[ ]的用法

>>> import re

>>> # 如果hello的首字符小写,那么正则表达式需要小写的h
>>> ret = re.match("h","hello Python")
>>> print(ret.group())
h

>>> # 如果hello的首字符大写,那么正则表达式需要大写的H
>>> ret = re.match("H","Hello Python")
>>> print(ret.group())
H

>>> # 大小写h都可以的情况
>>> ret = re.match("[hH]","hello Python")
>>> print(ret.group())
h
>>> ret = re.match("[hH]","Hello Python")
>>> print(ret.group())
H
>>> ret = re.match("[hH]ello Python","Hello Python")
>>> print(ret.group())
Hello Python

>>> # 匹配0到9第一种写法
>>> ret = re.match("[0123456789]Hello Python","7Hello Python")
>>> print(ret.group())
7Hello Python

>>> # 匹配0到9第二种写法
>>> ret = re.match("[0-9]Hello Python","7Hello Python")
>>> print(ret.group())
7Hello Python

>>> ret = re.match("[0-35-9]Hello Python","7Hello Python")
>>> print(ret.group())
7Hello Python

>>> # 下面这个正则不能够匹配到数字4,因此ret为None
>>> ret = re.match("[0-35-9]Hello Python","4Hello Python")
>>> print(ret.group())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'

示例3\\d用法

>>> import re

>>> # 普通的匹配方式
>>> ret = re.match("嫦娥1号","嫦娥1号发射成功")
>>> print(ret.group())
嫦娥1>>> ret = re.match("嫦娥2号","嫦娥2号发射成功")
>>> print(ret.group())
嫦娥2>>> ret = re.match("嫦娥3号","嫦娥3号发射成功")
>>> print(ret.group())
嫦娥3>>> # 使用\\d进行匹配
>>> ret = re.match("嫦娥\\d号","嫦娥1号发射成功")
>>> print(ret.group())
嫦娥1>>> ret = re.match("嫦娥\\d号","嫦娥2号发射成功")
>>> print(ret.group())
嫦娥2>>> ret = re.match("嫦娥\\d号","嫦娥3号发射成功")
>>> print(ret.group())
嫦娥3

其他的匹配符参见后面章节的讲解

3、匹配多个字符

匹配多个字符的相关格式

字符功能
*匹配前一个字符出现0次或者无限次,即可有可无
+匹配前一个字符出现1次或者无限次,即至少有1次
?匹配前一个字符出现1次或者0次,即要么有1次,要么没有
m匹配前一个字符出现m次
m,n匹配前一个字符出现从m到n次

示例1*用法

需求:匹配出,一个字符串第一个字母为大小字符,后面都是小写字母并且这些小写字母可有可无

>>> import re

>>> ret = re.match("[A-Z][a-z]*","M")
>>> print(ret.group())
M

>>> ret = re.match("[A-Z][a-z]*","MnnM")
>>> print(ret.group())
Mnn

>>> ret = re.match("[A-Z][a-z]*","Aabcdef")
>>> print(ret.group())
Aabcdef

示例2+用法

需求:匹配出,变量名是否有效

import re

names = ["name1", "_name", "2_name", "__name__"]

for name in names:
    ret = re.match("[a-zA-Z_]+[\\w]*",name)
    if ret:
        print("变量名 %s 符合要求" % ret.group())
    else:
        print("变量名 %s 非法" % name)

输出结果:

变量名 name1 符合要求
变量名 _name 符合要求
变量名 2_name 非法
变量名 __name__ 符合要求

示例3:?用法

需求:匹配出,0到99之间的数字

>>> import re

>>> ret = re.match("[1-9]?[0-9]","7")
>>> print(ret.group())
7

>>> ret = re.match("[1-9]?\\d","33")
>>> print(ret.group())
33

>>> ret = re.match("[1-9]?\\d","09")
>>> print(ret.group())
0 # 这个结果并不是想要的,利用$才能解决

示例4m用法

需求:匹配出,8到20位的密码,可以是大小写英文字母、数字、下划线

>>> import re

>>> ret = re.match("[a-zA-Z0-9_]6","12a3g45678")
>>> print(ret.group())
12a3g4

>>> ret = re.match("[a-zA-Z0-9_]8,20","1ad12f23s34455ff66")
>>> print(ret.group())
1ad12f23s34455ff66

4、匹配开头结尾

字符功能
^匹配字符串开头
$匹配字符串结尾

示例1^用法

需要:匹配以135开头的电话号码

>>> import re

>>> ret = re.match("^135[0-9]8","13588888888")
>>> print(ret.group())
13588888888

>>> ret = re.match("^135[0-9]8","13512345678")
>>> print(ret.group())
13512345678

# 136开头的没法匹配就会报错
>>> ret = re.match("^135[0-9]8","13688888888")
>>> print(ret.group())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'

示例2:$

需求:匹配出163的邮箱地址,且@符号之前有4到20位,例如hello@163.com

import re

email_list = ["xiaoWang@163.com", "xiaoWang@163.comheihei", ".com.xiaowang@qq.com"]

for email in email_list:
    ret = re.match("[\\w]4,20@163\\.com$", email)
    if ret:
        print("%s 是符合规定的邮件地址,匹配后的结果是:%s" % (email, ret.group()))
    else:
        print("%s 不符合要求" % email)

输出结果:

xiaoWang@163.com 是符合规定的邮件地址,匹配后的结果是:xiaoWang@163.com
xiaoWang@163.comheihei 不符合要求
.com.xiaowang@qq.com 不符合要求

5、匹配分组

字符功能
|匹配左右任意一个表达式
(ab)将括号中字符作为一个分组
\\num引用分组num匹配到的字符串
(?P<name>)分组起别名
(?P=name)引用别名为name分组匹配到的字符串

示例1|用法

需求:匹配出0-100之间的数字

>>> import re

>>> ret = re.match("[1-9]?\\d","8")
>>> print(ret.group())
8

>>> ret = re.match("[1-9]?\\d","78")
>>> print(ret.group())
78

>>> # 不正确的情况
>>> ret = re.match("[1-9]?\\d","08")
>>> print(ret.group())
0

>>> # 修正之后的
>>> ret = re.match("[1-9]?\\d$","08")
>>> if ret:
...     print(ret.group())
... else:
...     print("不在0-100之间")
...
不在0-100之间

>>> # 添加|
>>> ret = re.match("[1-9]?\\d$|100","8")
>>> print(ret.group())  # 8
8

>>> ret = re.match("[1-9]?\\d$|100","78")
>>> print(ret.group())  # 78
78

>>> ret = re.match("[1-9]?\\d$|100","08")
>>> # print(ret.group())  # 不是0-100之间

>>> ret = re.match("[1-9]?\\d$|100","100")
>>> print(ret.group())  # 100
100

示例2()用法

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

>>> import re

>>> ret = re.match("\\w4,20@163\\.com", "test@163.com")
>>> print(ret.group())
test@163.com

>>> ret = re.match("\\w4,20@(163|126|qq)\\.com", "test@126.com")
>>> print(ret.group())
test@126.com

>>> ret = re.match("\\w4,20@(163|126|qq)\\.com", "test@qq.com")
>>> print(ret.group())
test@qq.com

>>> ret = re.match("\\w4,20@(163|126|qq)\\.com", "test@gmail.com")
>>> if ret:
...     print(ret.group())
... else:
...     print("不是163、126、qq邮箱")
...
不是163126、qq邮箱

需求:不是以4、7结尾的手机号码(11位)

import re

tels = ["13100001234", "18912344321", "10086", "18800007777"]

for tel in tels:
    ret = re.match("1\\d9[0-35-68-9]", tel)
    if ret:
        print(ret.group())
    else:
        print("%s 不是想要的手机号" % tel)

输出结果:

18912344321
10086 不是想要的手机号
18800007777 不是想要的手机号

需求:提取区号和电话号码

>>> import re

>>> ret = re.match("([^-]*)-(\\d+)","010-12345678")
>>> print(ret.group())
010-12345678

>>> print(ret.group(1))
010

>>> print(ret.group(2))
以上是关于100天精通Python—第34天:正则表达式大总结的主要内容,如果未能解决你的问题,请参考以下文章

100天精通Python(进阶篇)——第40天:pymongo操作MongoDB数据库基础+代码实战

100天精通Python(数据分析篇)——第73天:Pandas文本数据处理方法之查找替换拼接正则虚拟变量

100天精通Python(数据分析篇)——第73天:Pandas文本数据处理方法之查找替换拼接正则虚拟变量

100天精通Python(基础篇)——第1天:Python和Vscode环境安装

100天精通Python(数据分析篇)——第51天:numpy函数进阶

100天精通Python(数据分析篇)——第52天:numpy完结