Python3 如何优雅地使用正则表达式(详解五)

2023-11-18

非捕获组命名组

精心设计的正则表达式可能会划分很多组,这些组不仅可以匹配相关的子串,还能够对正则表达式本身进行分组和结构化。在复杂的正则表达式中,由于有太多的组,因此通过组的序号来跟踪和使用会变得困难。有两个新的功能可以帮你解决这个问题——非捕获组和命名组——它们都使用了一个公共的正则表达式扩展语法。我们先来看看这个表达式扩展语法是什么。


正则表达式的扩展语法

众所周知,Perl 5 为标准的正则表达式增加了许多强大的功能。Perl 的开发者们并不能选择一个新的元字符或者通过反斜杠构造一个新的特殊序列来实现扩展的功能。因为这样会和标准的正则表达式发生冲突。比如你想选择  &  作为扩展功能的元字符(在标准正则表达式中, &  没有特殊意义),但这样的话,已经按照标准语法写出来的正则表达式就不得不修改,因为它们中包含的  '&'  意愿上只是把它当做普通字符来匹配而已。

小甲鱼解释:看起来很是头疼的兼容性问题,Perl 的开发者们是如何解决的呢?请接着看......


最终,Perl 的开发者们决定使用  (?...)  作为扩展语法。问号  ?  紧跟在左小括号  (  后边,本身是一个语法错误的写法,因为  ? 前边没有东西可以重复,所以这样就解决了兼容性的问题 (理由是语法正确的正则表达式肯定不会这么写嘛~) 。然后,紧跟在  ?  后边的字符则表示哪些扩展语法会被使用。例如  (?=foo)  表示一种新的扩展功能(前向断言), (?:foo)  则表示另一种扩展功能(一个包含子串  foo  的非捕获组)。

Python 支持 Perl 的一些扩展语法,并且在此基础上还增加了一个扩展语法。如果紧跟在问号  ?  后边的是  P ,那么可以肯定这是一个 Python 的扩展语法。

好,既然我们已经知道了如何对正则表达式的标准语法进行扩展,那我们回来看看这些扩展语法在复杂的正则表达式中是如何应用的。


非捕获组

第一个我们要讲的是非捕获组。有时候你知识需要用一个组来表示部分正则表达式,你并不需要这个组去匹配任何东西,这时你可以通过非捕获组来明确表示你的意图。非捕获组的语法是  (?:...) ,这个  ...  你可以替换为任何正则表达式。

  1. >>> m = re.match("([abc])+", "abc")
  2. >>> m.groups()
  3. ('c',)
  4. >>> m = re.match("(?:[abc])+", "abc")
  5. >>> m.groups()
  6. ()
复制代码

小甲鱼解释:“捕获”就是匹配的意思啦,普通的子组都是捕获组,因为它们能从字符串中匹配到数据。

除了你不能从非捕获组获得匹配的内容之外,其他的非捕获组跟普通子组没有什么区别了。你可以在里边放任何东西,使用重复功能的元字符,或者跟其他子组进行嵌套(捕获的或者非捕获的子组都可以)。

当你需要修改一个现有的模式的时候,(?:...) 是非常有用的。原始是添加一个非捕获组并不会影响到其他(捕获)组的序号。值得一提的是,在搜索的速度上,捕获组和非捕获组的速度是没有任何区别的。


命名组

我们再来看另外一个重要功能:命名组。普通子组我们使用序列来访问它们,命名组则可以使用一个有意义的名字来进行访问。

命名组的语法是 Python 特有的扩展语法: (?P<name>) 。很明显, < >  里边的  name  就是命名组的名字啦。命名组除了有一个名字标识之外,跟其他捕获组是一样的。

匹配对象的所有方法不仅可以处理那些由数字引用的捕获组,还可以处理通过字符串引用的命名组。除了使用名字访问,命名组仍然可以使用数字序号进行访问:

  1. >>> p = re.compile(r'(?P<word>\b\w+\b)')
  2. >>> m = p.search( '(((( Lots of punctuation )))' )
  3. >>> m.group('word')
  4. 'Lots'
  5. >>> m.group(1)
  6. 'Lots'
复制代码

命名组非常好用,因为它让你可以使用一个好记的名字代替一些毫无意义的数字。下边是来自 imaplib 模块的例子:

  1. InternalDate = re.compile(r'INTERNALDATE "'
  2.         r'(?P<day>[ 123][0-9])-(?P<mon>[A-Z][a-z][a-z])-'
  3.         r'(?P<year>[0-9][0-9][0-9][0-9])'
  4.         r' (?P<hour>[0-9][0-9]):(?P<min>[0-9][0-9]):(?P<sec>[0-9][0-9])'
  5.         r' (?P<zonen>[-+])(?P<zoneh>[0-9][0-9])(?P<zonem>[0-9][0-9])'
  6.         r'"')
复制代码

很明显,使用  m.group('zonem')  访问匹配内容要比使用数字 9 更简单明了。

正则表达式中,反向引用的语法像  (...)\1  是使用序号的方式来访问子组;在命名组里,显然也是有对应的变体:使用名字来代替序号。其扩展语法是  (?P=name) ,含义是该  name  指向的组需要在当前位置再次引用。那么搜索两个单词的正则表达式可以写成  (\b\w+)\s+\1 ,也可以写成  (?P<word>\b\w+)\s+(?P=word)

  1. >>> p = re.compile(r'(?P<word>\b\w+)\s+(?P=word)')
  2. >>> p.search('Paris in the the spring').group()
  3. 'the the'
复制代码


前向断言

我们要讲解的另一个零宽断言是前向断言,前向断言可以分为前向肯定断言和前向否定断言两种形式。

(?=...)

前向肯定断言。如果当前包含的正则表达式(这里以 ... 表示)在当前位置成功匹配,则代表成功,否则失败。一旦该部分正则表达式被匹配引擎尝试过,就不会继续进行匹配了;剩下的模式在此断言开始的地方继续尝试。


(?!...)

前向否定断言。这跟前向肯定断言相反(不匹配则表示成功,匹配表示失败)。


为了使大家更易懂,我们举个例子来证明这玩意是真的很有用。大家考虑一个简单的正则表达式模式,这个模式的作用是匹配一个文件名。我们都知道,文件名是用 . 将名字和扩展名分隔开的。例如在 fishc.txt 中,fishc 是文件的名字,.txt 是扩展名。

这个正则表达式其实挺简单的:

.*[.].*$

注意,这里用于分隔的 . 是一个元字符,所以我们使用 [.] 剥夺了它的特殊功能。还有 $,我们使用 $ 确保字符串剩余的部分都包含在扩展名中。所以这个正则表达式可以匹配 fishc.txt,foo.bar,autoexec.bat,sendmail.cf,printers.conf 等。

现在我们来考虑一种复杂一点的情况,如果你想匹配扩展名不是 bat 的文件,你的正则表达式应该怎么写呢?
我们先来看下你有可能写错的尝试:

.*[.][^b].*$

这里为了排除 bat,我们先尝试排除扩展名的第一个字符为非 b。但这是错误的开始,因为 foo.bar 后缀名的第一个字符也是 b

为了弥补刚刚的错误,我们试了这一招:

.*[.]([^b]..|.[^a].|..[^t])$

我们不得不承认,这个正则表达式变得很难看......但这样第一个字符不是 b,第二个字符不是 a,第三个字符不是 t......这样正好可以接受 foo.bar,排除 autoexec.bat。但问题又来了,这样的正则表达式要求扩展名必须是三个字符,比如sendmail.cf 就会被排除掉。

好吧,我们接着修复问题:

.*[.]([^b].?.?|.[^a]?.?|..?[^t]?)$

在第三次尝试中,我们让第二个和第三个字符变成可选的。这样就可以匹配稍短的扩展名,比如 sendmail.cf

不得不承认,我们把事情搞砸了,现在的正则表达式变得艰涩难懂外加奇丑无比!!


更惨的是如果需求改变了,例如你想同时排除 bat 和 exe 扩展名,这个正则表达式模式就变得更加复杂了......

当当当当!主角登场,其实,一个前向否定断言就可以解决你的难题:

.*[.](?!bat$).*$

我们来解释一下这个前向否定断言的含义:如果正则表达式 bat 在当前位置不匹配,尝试剩下的部分正则表达式;如果 bat匹配成功,整个正则表达式将会失败(因为是前向否定断言嘛^_^)。(?!bat$) 末尾的 $ 是为了确保可以正常匹配像sample.batch 这种以 bat 开始的扩展名。

同样,有了前向否定断言,要同时排除 bat 和 exe 扩展名,也变得相当容易:

.*[.](?!bat$|exe$).*$


原文地址:点击打开链接



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python3 如何优雅地使用正则表达式(详解五) 的相关文章

  • 人人都看得懂的正则表达式教程

    编写验证规则最流行和最简单的方法就是正则表达式了 但唯一的一个问题是正则表达式的语法太隐晦了 让人蛋疼无比 很多开发者为了在项目中应用复杂的验证 经常要使用一些小抄来记住正则式的复杂语法和各种常用命令 在这篇文章中 我将试图让大家明白什么是
  • VB.Net常用的正则表达式(实例)

    d 非负整数 正整数 0 0 9 1 9 0 9 正整数 d 0 非正整数 负整数 0 0 9 1 9 0 9 负整数 d 整数 d d 非负浮点数 正浮点数 0 0 9 0 9 1 9 0 9 0 9 1 9 0 9 0 9 0 9 1
  • Shell脚本攻略:通配符、正则表达式

    目录 一 理论 1 通配符 2 正则表达式 二 实验 1 通配符 2 正则表达式 一 理论 1 通配符 1 概念 通配符只用于匹配文件名 目录名等 不能用于匹配文件内容 而且是已存在的文件或者目录 各个版本的shell都有通配符 这些通配符
  • 正则表达式大全

    1 匹配中文 u4e00 u9fa5 2 英文字母 a zA Z 3 数字 0 9 4 匹配中文 英文字母和数字及下划线 u4e00 u9fa5 a zA Z0 9 同时判断输入长度 u4e00 u9fa5 a zA Z0 9 4 10 5
  • 常用js

    1 去掉字符串两端的空格 对字符串去两端空格 function stringTrim str if str null str undefined return null 用正则表达式将前后空格 用空字符串替代 return str repl
  • Java使用 java.util.regex.Pattern 正则表达式校验参数值是否规范

    场景 java中我们可以利用 Pattern 注解对某个入参进行规则校验 但有些特殊参数在接口入口处不方便校验 需要在代码中校验 一 使用 Pattern 注解校验 Pattern regexp a zA Z0 9 message xxx号
  • Web前端复习——JS(正则表达式+内置对象)

    正则表达式 专门规定字符中字符 格式规则 的表达式 何时使用 只要定义字符串格式规则 都用正则表达式 最简单正则 一个关键词的原文 就是最简单的正则 1 备选字符集 规定某 一位 字符可选的备选文字列表 语法 备选字符列表 强调 1 无论备
  • Nmap源码分析(服务与版本扫描)

    Nmap源码分析 服务与版本扫描 2012年8月23日 在进行端口扫描后 Nmap可以进一步探测出运行在端口上的服务类型及应用程序的版本 目前Nmap可以识别几千种服务程序的签名 Signature 覆盖了180多种应用协议 比如 端口扫描
  • Pattern.compile的flag参数

    Pattern compile函数 Pattern Pattern compile String regex int flag regex为正则表达式 flag的取值范围如下 Pattern CANON EQ 当且仅当两个字符的 正规分解
  • Java正则表达式详解

    1 1 正则表达式的概念以及演示 正则表达式可以用一些规定的字符来制定规则 并用来校验数据格式的合法性 正则表达式就是用来验证各种字符串的规则 它内部描述了一些规则 我们可以验证用户输入的字符串是否匹配这个规则 正则表达式是一种强大的校验机
  • re模块----你也可以玩得很溜正则表达式

    目录 re模块 compile pattern flags 0 flag匹配模式 match pattern string flags 0 search pattern string flags 0 findall pattern stri
  • 正则实现去除字符串前后空格

    前言 正则去掉字符串前后空格 1 去除左空格 str1是处理后的 let str1 str replace s g 2 去除右空格 str2是处理后的 let str2 str replace s g 3 去除左右空格 let str3 s
  • python爬虫之数据解析

    python爬虫之数据解析 正则表达式 bs4 xpath 主要运用在聚焦爬虫模块中 涉及到的数据解析方法有 正则表达式 bs4以及xpath 1 使用对象 聚焦爬虫 聚焦爬虫 爬取页面中指定的页面内容 2 数据解析原理概述 解析的局部的文
  • Java正则校验密码至少包含:字母数字特殊符号中的2种

    一 语法 字符 说明 将下一字符标记为特殊字符 文本 反向引用或八进制转义符 例如 n匹配字符 n n 匹配换行符 序列 匹配 匹配 匹配输入字符串开始的位置 如果设置了 RegExp 对象的 Multiline 属性 还会与 n 或 r
  • Python命令行参数定义及注意事项

    在命令行中运行python代码是很常见的 下面介绍如何定义命令后面跟的参数 常规用法 Python代码中主要使用下面几行代码来定义并获取需要在命令行中赋值的参数 import argparse parser argparse Argumen
  • js正则表达式多行匹配

    在js匹配网页内容时 往往需要匹配一段代码比如 div div 中间可能有很多行 这个时候一般 的匹配规则是匹配不出来的 如下介绍一个折中的方法 var content 这里是内容 var re p class s S p gt g var
  • 表示数值的字符串(含思路解答示意图)【剑指offer——JAVA实现】

    题目描述 请实现一个函数用来判断字符串是否表示数值 包括整数和小数 例如 字符串 100 5e2 123 3 1416 和 1E 16 都表示数值 但是 12e 1a3 14 1 2 3 5 和 12e 4 3 都不是 解法一 思路 状态机
  • Java 正则表达式工具类大全

    import java util regex Matcher import java util regex Pattern author nql Description 验证工具类 date now public class Validat
  • java OpenOffice把word转html(Convert word to html )

    1 下载安装OpenOffice 网址http download openoffice org index html 2 下载第三方工具包JODConverter http www artofsolving com opensource j
  • 【Python】Python 模式匹配与正则表达式

    Python 模式匹配与正则表达式 1 模式匹配与正则表达式 你可能熟悉文本查找 即按下Ctrl F 输入你要查找的词 正则表达式 更进一步 它们让你指定要查找的 模式 你也许不知道一家公司的准确电话号码 但如果你住在美国或加拿大 你就知道

随机推荐

  • Docker : docker: Error response from daemon: user specified IP address is supported on user defined

    1 美图 2 背景 想运行docker容器的时候 指定ip 但是发现出问题 base lcc lcc docker run d name es2 ip 172 16 12 12 p 9200 9200
  • 如何将你的iOS应用成功上架App Store(图文详解)

    上架基本需求资料 1 苹果开发者账号 如还没账号先申请 苹果开发者账号申请教程 2 开发好的APP 通过本篇教程 可以学习到ios证书申请和打包ipa上传到appstoreconnect apple com进行TestFlight测试然后提
  • “北漂”小夫妻新婚后的理财计划

    北漂 小夫妻新婚后的理财计划 提要 经过多年的努力打拼 1976 年出生的姜帆终于在京城站稳脚跟 做上了一家大公司的业务主管 今年 十一 国庆节还 和谈了多年马拉松恋爱的女友举行了婚礼 面对婚后新形势下几个令他烦恼的家庭理财目标 他该如何应
  • VNC VIEWER 连接闪退不断重新连接的解决办法

    1 vnc viewer官网下载standalone 2 vnc链接 3 连接后不断闪退 又不断重连 根本无法进行任何操作或操作困难 解决办法 1 2 点击properties 3 点击options general 调低画质
  • C语言好题解析(一)

    目录 选择题1 选择题2 选择题3 选择题4 编程题一 选择题1 执行下面程序 正确的输出是 int x 5 y 7 void swap int z z x x y y z int main int x 3 y 8 swap printf
  • 在Linux上面进行远程git的数据拉取与上传

    1 安装git sudo apt get update sudo apt get install git 2 查看本地git信息 git version 3 在当前路径下创建一个本地git仓库 sudo git init 4 上传当前的文件
  • TIM输出比较

    以下内容均来自 bilibili江协科技 OC输出比较 输出比较可以通过CNT与CCR寄存器值的关系 来对输出电平进行置1 置0或翻转的操作 用于输出一定频率和占空比的PWM波形 每个高级定时器和通用定时器都拥有4个输出比较通道 高级定时器
  • 正负号 substr java_实战LeetCode 系列(一) (题目+解析)

    1 反转字符串 编写一个函数 其作用是将输入的字符串反转过来 示例 1 输入 hello 输出 olleh 示例 2 输入 A man a plan a canal Panama 输出 amanaP lanac a nalp a nam A
  • 8.性能测试流程及策略

    8 性能测试流程及策略 一 准备工作 1 系统基础功能验证 性能测试在什么阶段适合实施 切入点很重要 一般而言 只有在系统基础功能测试验证完成 系统区域稳定的情况下 才会进行性能测试 否则性能测试是无意义的 2 测试团队组建 根据项目的具体
  • 高防cdn有什么优势?

    CDN即内容分发网络 通过在网络上各处放置节点服务器 来协助网站进行缓存 当用户访问网站时 就近分配节点为用户提供服务 从而加快访问速度 提升用户体验 但是普通的cdn并没有防御能力 那么这时就需要用到高防cdn来应对网络上的攻击 下面为大
  • Matlab:从文本文件中读取数值数据到矩阵

    Matlab 从文本文件中读取数值数据到矩阵 在Matlab中 我们常常需要将保存在文本文件中的数值数据读取到程序中 以便进行数据处理和分析 本文将介绍如何使用Matlab将文本文件中的数值数据导入到矩阵中 首先 我们需要创建一个文本文件
  • pandas-新手使用教程

    Pandas 是 Python 语言的一个扩展程序库 用于数据分析 下面将针对该模块进行讲解 一 导入模块 导入pandas模块 import pandas as pd 二 导入数据 常见用法 创建数据框 pd DataFrame 从CSV
  • C# --- Case Study

    C Case Study C Mongo数据库事务的应用 C 如何解析Json文件并注入MongoDB C MongoDB如何安全的替换Collection C netcore MVC项目框架结构 with MongoDB
  • 积分获取方式的两点优化建议

    积分获取是积分体系运营中的一个重要环节 也是针对用户运营的一个开端 如果积分获取做的不到位 那么商家就没法对用户的行为进行引导 也就没法实现商家的预期目标 整个积分体系就相当于白忙活了 这一点商家要特别的注意 在积分体系运营中 商家对于积分
  • 网课-cnn

    图像识别中遇到的问题可能有图片特征的纬度过高 1000 1000像素的图片 特征维度是1000 1000 3 如果你要输入3百万的数据量就意味着特征向量的维度高达三百万 也许有1000个隐藏单元 而所有的权值组成的矩阵W 1 如果使用标准的
  • git第一次配置ssh key,clone代码出错解决方法

    错误 The authenticity of host can t be established ED25519 key fingerprint is SHA256 k4ViHJBFryacGI BqHphyjDBaRLwt5eSGRMJG
  • vue table合并行 动态列名

    需求 1 合并行 相同数据合并 2 根据后端返回数据动态显示列名 我这个业务需求是 每年增加一列 也就是列名不是固定的 后端返回数据每年会多一条数据 根据返回数据显示列名 实现 html
  • 论文阅读 StyleCLIP:《StyleCLIP: Text-Driven Manipulation of StyleGAN Imagery》

    论文地址 https arxiv org pdf 2103 17249 pdf 文章目录 摘要 1 介绍 2 相关工作 2 1 视觉与语言 2 2 潜空间图像处理 3 StyleCLIP文本驱动操作 4 潜在优化 5 潜在映射 6 全局方向
  • 解密蓝牙mesh系列

    转载自 蓝牙技术联盟 蓝牙mesh网络 友谊篇 低功耗蓝牙 Bluetooth Low Energy 是全球最具节能性的短距离无线通信技术之一 其低功耗的特性广受开发者和消费者赞誉 随着蓝牙mesh网络的推出 开发者可能想知道蓝牙mesh网
  • Python3 如何优雅地使用正则表达式(详解五)

    非捕获组命名组 精心设计的正则表达式可能会划分很多组 这些组不仅可以匹配相关的子串 还能够对正则表达式本身进行分组和结构化 在复杂的正则表达式中 由于有太多的组 因此通过组的序号来跟踪和使用会变得困难 有两个新的功能可以帮你解决这个问题 非