正则表达式高阶技巧之匹配模式(使用python实现)
创始人
2025-05-29 04:30:03

匹配模式

    • 介绍
      • 不区分大小写模式
        • 模式的指定方式
        • 应用
      • 单行模式
      • 多行模式
      • 注释模式
      • 其它模式
    • 修饰符的作用范围

介绍

  • 我们在正则中所说得匹配模式(match mode),指的是匹配时使用的规则。设置特定的匹配模式,可能会改变对正则表达式的识别,也可能会改变正则表达式中字符的匹配规定
  • 常见的匹配模式一共有四种:不区分大小写模式、单行模式、多行模式、注释模式

不区分大小写模式

  • 在日常使用中,用户可能关心的只是文本的意义,而不是它具体形式。比如单词the,在句子中写作the,在句子开头写做The,还可能为了表示强调写作THE;可是用户可能不关心大小写,只希望找到所有的the
  • 为了实现上述需求,我们可以使用字符组[tT][hH][eE],这样的写法是没有问题的,但是如果单词较长,写起来就是比较麻烦的。比如:beautiful就要写成[bB][eE][aA][uU][tT][iI][fF][uU][lL]。更重要的是,这样的表达式不够直观,很难明白此表达式要匹配的是beautiful
  • 为了解决上述的问题,正则表达式提供了不区分大小写的匹配模式,指定此模式之后,在正则表达式中可以直接写the,就可以匹配the、THE、The、THe等等各种大小写形式的the,提升了直观程度,还大大降低了理解的难度

模式的指定方式

  • 在了解此模式的应用实例之前,必须要先了解模式的指定方式。通常是有两种方法来指定匹配模式的:以模式修饰符指定,或者以预定义常量作为特殊参数传入来指定

模式修饰符

  • 模式修饰符即模式对应的单个字符,使用时将其填入特定结构(?modifier)(其中modifier为模式修饰符),嵌在正则表达式的开头。比如不区分大小写的模式对应的模式修饰符是i(case Insensitive),对于the来指定此模式,完整的表达式为(?i)the
    如下举例:
import re
re.search(r"(?i)beautiful",'beautiful') is not None
re.search(r"(?i)beautiful",'Beautiful') is not None
re.search(r"(?i)beautiful",'BEAUTIFUL') is not None

在这里插入图片描述
预定义好的常量作为特殊参数传入来指定

  • 我们可以使用预定义好的常量作为参数,传入正则函数
  • 在python中不区分大小写的预定义常量是Re类的静态成员re.IGNORECASE(一般来说。它是某个类的静态成员)
语言常量
pythonre.I或re.IGNORECASE

如下举例:

import re
re.search(r"beautiful",'beautiful',re.I) is not None
re.search(r"beautiful",'Beautiful',re.IGNORECASE) is not None

在这里插入图片描述

  • 上述的两种指定方式,模式描述符较为通用,因为在常用的语言中写法基本相同,而预定义常量在不同语言中写法不同,不过上述的两种形式的效果是相同的:无论是以那种方式,只要指定不区分大小写模式,正则表达式在匹配时,就不会区分同一个字母的大小写形式,即(?i)the(?i)THE是完全等价的

应用

  • 在之前匹配HTML最终tag的例子中,比如匹配超链接tag的正则表达式、匹配图片tag及网页标题tag的正则表达式,虽然在HTML规范推荐tag名都使用小写字母,但类似的的tag还是可能出现的,为了同时兼容大写字母,可以使用不区分大小写模式,如下表格:
描述表达式
提取超链接(?i)([^<]+)
提取标题(?i)([^>]+)
提取图片(?i)]*?src=['"]?([^'"]+)['"]?[^>]*>

单行模式

  • 元字符.几乎可以匹配任何字符,唯有换行符\n是例外。但是,有是否确实需要匹配“任何字符”,比如我们在处理爬取到的HTML源码时,经常需要跨越多行取数据,如下:

  • 正则文档里一般都会说明“.不能匹配换行符”,不过部分人并不阅读与深究文档,所以认为.点号能匹配任何字符,当然也包括换行符,所以直接想法就是
  • 因为这段代码出现了换行符,所以.*?的匹配最多只能进行到第一行末尾,可以使用[\s\S]之类的字符组匹配“任意字符”,所以正则表达式能解决问题
  • 不过对于大部分人来说,点号更加自然,也更加直观简洁,所以正则表达式提供单行模式,在这个模式下,所有的文本似乎只在一行里,换行符是这一行中的“普通字符”,所以可以使用.来进行匹配
  • 重点在于是将单行模式中的文本看成一行
  • 单行模式对应的模式修饰符是s(Single line),所以如果要使用单行模式,只需要在表达式的开头用(?s)指定,因此上面的表达式可以修改为(?s)

预定义常量如下:

语言常量
pythonre.S或re.DOTALL

多行模式

  • “多行模式”听起来是与上述的“单行模式”对应的,但其实这两个模式是没有任何联系的
  • 单行模式影响的是.点号的匹配规则:在默认的模式下,点号.可以匹配除换行符之外的任何字符,在单行模式下点号可以匹配包括换行符在内的任何字符
  • 多行模式影响的是^$的匹配规则:在默认的模式下^$匹配的是整个字符串的起始位置与结束位置,但是在多行模式下,它们也能匹配字符串内部某一行文本的起始位置和结束位置
  • 如下举例,需要找到下面文本中所有以数字字符开头的行:
1 one
No ycx
Yes wy
2 two
  • 为解决此问题,需要定位到每一行的起始位置,尝试匹配一个数字字符,如果成功,则匹配之后的整行文本。多行模式的模式修饰符是m(Multiline),所以在表达式中的开头用(?m)指定多行模式,这样^就可以定位到字符串内部的每一行的起始位置;匹配数字字符的表达式为\d,因为没有指定单行模式。.点号是不能匹配换行符的,.*可以匹配数字字符之后的整行文本,所以表达式就是(?m)\d.*

如下测试:

import remultiStr = """
1 one
No ycx
Yes wy
2 two
"""multiRegex = r"(?m)\d.*"
for line in re.findall(multiRegex, multiStr):print(line)

在这里插入图片描述

  • 还可以利用多行模式下的$,给每一行末尾添加英文句号.,如下:
import re
multiStr = """1 one
No ycx
Yes wy
2 two"""
print(re.sub(r'(?m)$','.',multiStr))

在这里插入图片描述

  • 预定义常量如下:
语言常量
pythonre.M或re.MUTILINE

注释模式

  • 在某些情况下,用到的正则表达式可能是非常复杂的,不但难以编写和阅读,也难以维护,如果正则表达式也可以像编程语言源代码那样,可以添加注释,阅读与维护就容易多了
  • 为解决上述问题,多数语言是支持使用(?#comment)的记法添加注释,comment是注释内容。所以,在我们的表达式^\d.*?$就可以写成这样:^(?#start of the line)\d(?#digit).*?(?#rest of the line)
  • **.NET、Python、Ruby、PHP都是支持这种写法的,Java和JavScript则不支持,不过,还有一种注释的写法是各种语言都支持的,就是使用注释模式,此时,正则表达式对应的字符串可以跨越很多行,如下举例:
import re
multiStr = """1 one
No ycx
Yes wy
2 two"""LineBeginRegex = r"""
(?mx) #enable multiline and extended mode
^    # start of the line
\d   #digit
.*   # est of the line
$    #end of the line
"""
re.findall(LineBeginRegex, multiStr)

在这里插入图片描述

  • 在注释模式下,正则表达式内部的空白字符都会被忽略(一般来说,只要是ASCII编码中的空白字符,Unicode编码中的空白字符清空不定),注释则以#comment的形式添加在正则表达式内部,每一条注释从#开始,到行末结束。在许多的文档,都是用这种模式来解释较为复杂的表达式,并且会使用缩进表示层级结构,这样就更加方便阅读和维护。
  • 如下举例匹配日期的正则表达式((?x)(\d{4})-(\d{2})-(\d{2})),在注释模式下的展开:
dateRegex=r"""
(?x)        # enable multiline ans extended mode
(           # start of the regex(\d{4}) # year-       # dash(\d{2}) # month-       # dash(\d{2}) # day
)           # end of the regex
"""
re.search(dateRegex,"2022-01-02").group()

在这里插入图片描述

  • 注释模式对应的修饰符是x(extended mode,扩展模式,但是更常见的写法是free-spacing mode,宽松格式模式)
  • 预定义常量如下:
语言常量
pythonre.X或re.VERROSE
  • 在上述例子,我们同时制定了两种模式:多行模式与注释模式。注释模式的x与多行模式的m,合在一起写作(?mx)。如果需要同时使用多种匹配模式,只要在(?modifier)中将模式修饰符排列起来即可
  • 如果希望同时使用多行模式与注释模式,使用预定义常量该怎么做?答案是,使用位运算符|,通常来说对应的预定义常量都是int类型,所以多个值进行按位与的结果,并不会彼此干扰,在python中是这样的re.M | re.X,如下:
import remultiStr = """1 one
No ycx
Yes wy
2 two"""LineBeginRegex = r"""
^    # start of the line
\d   #digit
.*   # est of the line
$    #end of the line
"""
re.findall(LineBeginRegex, multiStr, re.M | re.X)

在这里插入图片描述

其它模式

python的还包含有其他模式(这里仅列举两种,更多的请查阅文档):

  • re.U或re.UNICODE:在此模式下。\d \w \s等字符组简记法的匹配规则会发生改变,比如\w能匹配Unicode中的“单词字符”,包括中文字符,\d也能匹配1、2之类的全角数字字符,对应的模式修饰符是u
  • re.A或re.UNICODE:因为在python 3以上的版本中,正则表达式默认采用Unicode匹配规则,如果希望\d \w等字符组简记法恢复到ASCII匹配规则,可以使用此模式,对应的模式修饰符是a

修饰符的作用范围

  • 常见的模式修饰符为(?modifier)的形式,它表示从现在开始使用此模式,通常的做法是将它写在正则表达式的开头,表示整个正则表达式都指定使用此模式;如果它出现正则表达式中,则表示此模式从这里开始生效,但是在python中情况不同,只要模式修饰符(?modifier)出现,无论出现在什么位置,都对整个正则表达式生效;如下:
re.search(r"t(?i)he","THE").group()

在这里插入图片描述

  • 如果模式修饰符出现在某个括号内,如((?modifier).....)那它的作用范围只限于括号内部,此模式也可记为(?modifier:.....)

如下举例:

正则表达式可匹配的文本
t(?i)hetHE the tHe thE
th(?i)ethe thE
t((?i)h)etHe the
t(?i:h)etHe the
  • 模式修饰符对正则表达式的操作性更强,因为预定义常量指定的匹配模式是对整个正则表达式生效的

相关内容

热门资讯

【实验报告】实验一 图像的... 实验目的熟悉Matlab图像运算的基础——矩阵运算;熟悉图像矩阵的显示方法࿰...
MATLAB | 全网最详细网... 一篇超超超长,超超超全面网络图绘制教程,本篇基本能讲清楚所有绘制要点&#...
大模型落地比趋势更重要,NLP... 全球很多人都开始相信,以ChatGPT为代表的大模型,将带来一场NLP领...
Linux学习之端口、网络协议... 端口:设备与外界通讯交流的出口 网络协议:   网络协议是指计算机通信网...
kuernetes 资源对象分... 文章目录1. pod 状态1.1 容器启动错误类型1.2 ImagePullBackOff 错误1....
STM32实战项目-数码管 程序实现功能: 1、上电后,数码管间隔50ms计数; 2、...
TM1638和TM1639差异... TM1638和TM1639差异说明 ✨本文不涉及具体的单片机代码驱动内容,值针对芯...
Qt+MySql开发笔记:Qt... 若该文为原创文章,转载请注明原文出处 本文章博客地址:https://h...
Java内存模型中的happe... 第29讲 | Java内存模型中的happen-before是什么? Java 语言...
《扬帆优配》算力概念股大爆发,... 3月22日,9股封单金额超亿元,工业富联、鸿博股份、鹏鼎控股分别为3.0...
CF1763D Valid B... CF1763D Valid Bitonic Permutations 题目大意 拱形排列࿰...
SQL语法 DDL、DML、D... 文章目录1 SQL通用语法2 SQL分类3 DDL 数据定义语言3.1 数据库操作3.2 表操作3....
文心一言 VS ChatGPT... 3月16号,百度正式发布了『文心一言』,这是国内公司第一次发布类Chat...
CentOS8提高篇5:磁盘分...        首先需要在虚拟机中模拟添加一块新的硬盘设备,然后进行分区、格式化、挂载等...
Linux防火墙——SNAT、... 目录 NAT 一、SNAT策略及作用 1、概述 SNAT应用环境 SNAT原理 SNAT转换前提条...
部署+使用集群的算力跑CPU密... 我先在开头做一个总结,表达我最终要做的事情和最终环境是如何的,然后我会一...
Uploadifive 批量文... Uploadifive 批量文件上传_uploadifive 多个上传按钮_asing1elife的...
C++入门语法基础 文章目录:1. 什么是C++2. 命名空间2.1 域的概念2.2 命名...
2023年全国DAMA-CDG... DAMA认证为数据管理专业人士提供职业目标晋升规划,彰显了职业发展里程碑及发展阶梯定义...
php实现助记词转TRX,ET... TRX助记词转地址网上都是Java,js或其他语言开发的示例,一个简单的...
【分割数据集操作集锦】毕设记录 1. 按要求将CSV文件转成json文件 有时候一些网络模型的源码会有data.json这样的文件里...
Postman接口测试之断言 如果你看文字部分还是不太理解的话,可以看看这个视频,详细介绍postma...
前端学习第三阶段-第4章 jQ... 4-1 jQuery介绍及常用API导读 01-jQuery入门导读 02-JavaScri...
4、linux初级——Linu... 目录 一、用CRT连接开发板 1、安装CRT调试工具 2、连接开发板 3、开机后ctrl+c...
Urban Radiance ... Urban Radiance Fields:城市辐射场 摘要:这项工作的目标是根据扫描...
天干地支(Java) 题目描述 古代中国使用天干地支来记录当前的年份。 天干一共有十个,分别为:...
SpringBoot雪花ID长... Long类型精度丢失 最近项目中使用雪花ID作为主键,雪花ID是19位Long类型数...
对JSP文件的理解 JSP是java程序。(JSP本质还是一个Servlet) JSP是&#...
【03173】2021年4月高... 一、单向填空题1、大量应用软件开发工具,开始于A、20世纪70年代B、20世纪 80年...
LeetCode5.最长回文子... 目录题目链接题目分析解题思路暴力中心向两边拓展搜索 题目链接 链接 题目分析 简单来说࿰...