正则表达式(6):分组与后向引用

news2024/9/24 13:15:27

正则表达式(6):分组与后向引用

      • 总结

本博文转载自

在本博客中,”正则表达式”为一系列文章,如果你想要从头学习怎样在Linux中使用正则,可以参考此系列文章,直达链接如下:

在Linux中使用正则表达式

“正则”系列的每篇文章都建立在前文的基础之上,所以,请按照顺序阅读这些文章,否则有可能在阅读中遇到障碍。

前文中,已经总结了正则表达式中的常用字符、次数匹配、位置匹配等,这篇文章中,我们来了解一下正则中的”分组”与”后向引用”。

什么是分组?什么是后向引用?我们慢慢聊。

先来说说什么是分组。

算了,思考了半天,我也不知道从何说起,先看个示例吧,根据示例去描述反而更加清晰,示例如下。

在这里插入图片描述

上述示例中,我们使用到了之前所了解到的”连续次数匹配”,”{2}”表示其前面的字符连续出现的2次,即可被匹配到。

但是,正如上图所示,”\{2\}”所影响的字符只是其前面的单个字符,也就是上例中的字母o

所以,上例中,helloo被匹配到了,hellooo也被匹配到了,因为”hell”字符串后面的确出现了2次字母o

但是,如果我们想要从上例中的文本中找出,2次连续出现的hello字符串,该怎么办呢?

正如你所看到的,”hello\{2\}”并不能表示”hellohello”,它只能表示”helloo”,那么,我们该怎么办呢?

这个时候,我们就需要用到”分组”,将”hello”当做一个”分组”,当做一个”整体”,才可以达到我们的目的,示例如下

在这里插入图片描述

正如上图所示,”\(hello\)”表示将hello字符串当做一个整体,所以,”\{2\}”所影响的字符就是前面的”hello字符串”(这个整体)。

所以,”\(hello\)\{2\}”这个正则表达式就表示hello字符串连续出现两次,也就是”hellohello”

没错,”\( \)”就表示分组。

“\( \)”表示将其中的内容看做一个分组,看做一个整体。

分组还可以嵌套,什么意思呢?我们来看一个例子。

在这里插入图片描述

上图中的正则表达式猛一看有些复杂,但是我们一点一点的拆开来看,就比较容易理解了,没错,我们先按照上图所示,将”红线部分”与”蓝线部分”拆成两部分

蓝线部分为”\{2\}”,表示之前的字符连续出现两次

红线部分为”\(ab\(ef\)\{2\}\)”,可以看到,红线部分的两侧正好由”\( \)”组成,由此可见,红线部分应该作为一个整体,应该作为一个分组被操作,再结合之前的蓝线部分,即可得知,红线部分应该作为一个整体连续出现两次。

那么,我们把红线部分最外侧的”\( \)”去掉,红线部分内侧的正则为”ab\(ef\)\{2\}”,可以看到,红线部分内侧的正则中还有一组分组符号,就是”(ef)”,这个分组符号把ef当做了一个整体,所以,”ab\(ef\)\{2\}”表示字符串ab后面跟随了2个连续出现的ef,那么,”ab\(ef\)\{2\}”就表示字符串”abefef”。

逆推回去,我们把红线内侧的正则替换为”abefef”,于是,上例中的正则就表示”\(abefef\)\{2\}”,最终如上图所示,2次连续出现的abefef被匹配到了。

上例中,红线部分一共包含两个分组符号,最外侧的”\( \)”中又包含了另一个”\( \)”,这就是分组符号的嵌套。

我想,我应该说清楚了。

那么,我们再来聊聊什么是后向引用。

之所以先介绍分组,是因为后向引用是以分组为前提的,如果想要实现后向引用,则必须先进行分组。

那么”后向引用”是什么意思呢?

如果直接放出概念,我不容易描述,你也不容易理解,我们还是先来看个小例子吧,示例文件如下。

在这里插入图片描述

如果我们想要使用正则去匹配上述示例中的两行文本,我们改怎么办呢?

我们可以使用如下正则表达式去匹配。

在这里插入图片描述

“H.\{4\}”表示大写字母H的后面跟随了4个任意字符,其中”.”表示任意单个字符,我们在前文中已经举例演示过,此处不再赘述。

所以,”H.\{4\}”既可以匹配到Hello,也可以匹配到Hiiii,那么,上述两行文本都被匹配到了。

此时,我们修改一下示例文件,在示例文件中再添加一行测试文本,修改后的测试文件内容如下

在这里插入图片描述
如上图所示,我们添加了一行文本,这行文本以Hello开头,以Hiiii结尾。

我们使用刚才的正则,能够匹配到这一行新添加的文本吗,我们来试试。

在这里插入图片描述

可以看到,新添加的一行文本也被匹配到了,因为”H.\{4\}”表示大写字母H的后面跟随了4个任意字符,最后一行也满足条件,所以也被匹配到了。

但是此刻,我有了新需求~~

我只想从上例中找出”world”前后单词相同的那些行,换句话说就是,world之前的单词是Hello,world之后的单词也要是Hello,world之前的单词是Hiiii,world之后的单词也要是Hiiii,只有这种行满足条件。

上例中第三行则不满足条件,因为上例的第三行中,world之前的单词是Hello,而world之后的单词是Hiiii,前后不一致,所以不满足我的条件。

那么我该怎么办呢?之前的正则肯定不行,因为之前的正则也能够将上例中的第三行匹配到。

这个时候,就需要用到”后向引用”,示例如下。

在这里插入图片描述

可以看到,使用上述正则,即可达到我们的目的,只有world前后的单词完全相同时,才会被匹配到。

那么,上例中的正则是什么意思呢?我们仍然拆成两部分来介绍,以便我们理解。

上例的红线部分为:“\(H.\{4\}\)”`
上例的蓝线部分为:”\1″

红线部分的正则与之前示例中的正则只有一点点区别,就是在原来的基础之上添加了分组,将”H.\{4\}”变成了”\(H.\{4\}\)”,但是它的大概含义并没有改变,”\(H.\{4\}\)”表示大写字母H的后面跟随了4个任意字符,并且字母H与后面的4个字符将作为一个整体。那么,为什么要在原来的基础上添加分组呢?这是因为,如果想要实现后向应用,则必须以分组为前提,现在我们暂且不纠结这一点,之后回过头来看,就会明白。

蓝色部分的正则为”\1″,它有什么含义呢?

“\1″表示整个正则中第1个分组中的正则所匹配到的结果,这样说可能不容易理解,我们用大白话说一遍。

在上例中,整个正则中只出现了1个分组,就是”\(H.\{4\}\)”,当它与示例文件中的第一行文本进行匹配时,会匹配到Hello字符串,这时,”\1″就表示Hello字符串。

当正则”\(H.\{4\}\)”与示例文件中的第二行文本进行匹配时,会匹配到Hiiii字符串,这时,”\1″就表示Hiiii字符串。

也就是说,”\1″必须与整个正则中第1个分组中的正则(也就是红色部分的正则)所匹配到的结果相同。

换句话说就是,”\1″引用了整个正则中第1个分组中的正则(也就是红色部分的正则)所匹配到的结果。

如果你还没有懂,看图理解吧。

在这里插入图片描述

现在回头想想,你知道为什么必须为”H.\{4\}”添加分组了吗?因为,当我们为”H.\{4\}”添加了分组以后,”H.\{4\}”就变成了整个正则中第1个分组中的正则,当”H.\{4\}”匹配到的结果为Hello时,”\1″就引用了Hello,当”H.\{4\}”匹配到的结果为Hiiii时,”\1″就引用了Hiiii。

这就是所谓的”后向引用”。

上述描述看一遍可能不容易立马理解,可以重复仔细的多看几遍,慢慢就会理解了。

聪明如你,一定想到了。

“\1″表示引用整个正则中第1个分组中的正则所匹配到的结果,那么,”\2″呢?没错,正如你所想。

“\2″表示引用整个正则中第2个分组中的正则所匹配到的结果

示例如下

在这里插入图片描述

如上图所示,”\2″引用了上图中”绿线部分的正则”所匹配到的结果,而上图中”绿线部分的正则”就是”整个正则表达式中第2个分组中的正则”。

那么,以此类推,”\3″、”\4″、”\5″、”\6″所表达的意思就不言而喻了。

再次强调,使用后向引用的前提是将需要引用的部分分组。

不过,当分组嵌套时,我们应该怎样区分哪个分组是第1个分组,哪个分组是第2个分组呢?

我们通过一个小示例,即可明白,为了尽量简化整个正则,我们直接将一些字符分组即可,示例如下。

在这里插入图片描述
上述正则表达式中,一共出现了两个分组,一个分组嵌套着另一个分组。

在这里插入图片描述

可以从上图中看出,红色标注的符号是一对分组符号,蓝色标注的符号是一对分组符号,红色分组嵌套这蓝色分组。

虽然上例中没有使用到”后向引用”,但是,当我们需要使用”后向引用”时,这两个分组哪个才是第1个分组,哪个是第2个分组呢?

当我们需要使用后向引用时,红色分组为第1个分组,蓝色分组为第2个分组。

换句话说就是,当使用后向引用时,”\1″引用的是红色分组所匹配的结果,”\2″引用的是蓝色分组所匹配的结果。

为什么呢?原因就是,分组的顺序取决于分组符号的左侧部分的顺序,如下图所示

在这里插入图片描述

由于红色分组的左侧部分排在最前面,所以红色分组是整个正则中的第1个分组。

由于蓝色分组的左侧部分排在第2位,所以蓝色分组是整个正则中的第2个分组。

注意:排序时也仅仅按照分组符号的左侧部分排序,分组符号的右侧部分不算在排序范围内。

好了,”分组”与”后向引用”就总结到这里,我想我应该说明白了,描述起来好费力~~~希望能够帮到你。

之前说过,在Linux中,正则表达式分为基础正则表达式与扩展正则表达式。

而我们之前所描述的符号都属于基本正则表达式。

在以后的文章中,我们会接触到扩展正则表达式,但是不用害怕,它们的用法都是相似的,而且写法也差不多,学会基本正则表达式以后,再学习扩展正则表达式,几乎不会费力。

总结


为了方便以后回顾,我们将今天了解到的只是进行总结。

\( \) 表示分组,我们可以将其中的内容当做一个整体,分组可以嵌套。

\(ab\) 表示将ab当做一个整体去处理。

\1 表示引用整个表达式中第1个分组中的正则匹配到的结果。

\2 表示引用整个表达式中第2个分组中的正则匹配到的结果。

这篇文章就总结到这里,希望能够帮助到你~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1310927.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ThinkPHP连接ORACLE数据库教程

目录 概念基本步骤详细操作问题排除参考 概念 要连接Oracle数据库,必须有两个东西,一个PHP官方写的扩展,一个Oracle官方写的客户端PHP是通过扩展去操作oralce客户端连接的服务端数据库,所以两个都不能少,而且版本必须…

arthas统计大循环方法时的注意事项

背景 arthas是我们日常查找各种问题的利器,不过我们也需要意识到arthas本身也是有性能损耗的,所以当老板对你提问为什么使用arthas分析时这个方法比生产上正常运行时这个方法的耗时要长很多,你可以向他进行解释,进而由于arthas的…

边缘检测@获取labelme标注的json黑白图掩码mask

import cv2 as cv import numpy as np import json import os from PIL import Imagedef convertPolygonToMask(jsonfilePath):

MySQL——数据类型

目录 一.数据类型分类 二. 数值类型 1.tinyint类型 2.bit类型 3.float类型 4.decimal 三.字符串类型 1.char 2.varchar 四.日期和时间类型 五.enum和set 一.数据类型分类 关于数据库的数据类型有非常多,但是并非所有的数据类型都是我们常用的&#xff…

《信息技术时代》期刊杂志论文发表投稿

《信息技术时代》期刊收稿方向:通信工程、大数据、计算机、办公自动化、信息或计算机教育、电子技术、系统设计、移动信息、图情信息研究、人工智能、智能技术、信息技术与网络安全等。 刊名:信息技术时代 主管主办单位:深圳湾科技发展有限…

vs2019比较两个代码的区别方法

vs2019比较两个代码的区别方法 效果代码 效果 代码 Tools.DiffFiles 3d_mig(1).c 3d_mig_xin0.c

UDP内网穿透和打洞原理与代码实现

1、众所周知,现在主流网络用的还是IPV4协议,理论上一共有2^3243亿个地址,除去私有网段、网络ID、广播ID、保留网段、本地环回127.0.0.0网段、组播224.0.0.0网段、实际可用就是36.47亿个;全球的服务器、PC机、手机、物联网设备等需…

08.CSS盒模型

CSS盒模型 1.介绍 CSS 会把所有的 HTML 元素都看成一个盒子,所有的样式也都是基于这个盒子 2.盒模型构成 介绍 margin(外边距):盒子与外界的距离border(边框):盒子的边框padding&#xff0…

美国如果把根域名服务器封了,中国不会从网络上消失

目录 美国如果把根域名服务器封了,中国不会从网络上消失为什么根服务器最多13个 输入URL后发生了什么 参考 https://www.yuque.com/fcant/network/vhyvik#AuOqk 美国如果把根域名服务器封了,中国不会从网络上消失 来源: https://segmentfau…

TwinCAT3 Modbus-TCP Client/Server使用

目录 一、环境配置和准备 1、PLC中安装TF6250-Modbus-TCP库 2、勾选TF6250的license 3、PLC工程中添加Tc2_ModbusSrv库文件 4、分别创建测试ModbusTCP测试的Server和Client程序 二、PLC作为Client端 1、设置测试电脑IP地址 2、运行MobusTCP测试工具 3、PLC端程序编写 …

基于C/C++的rapidxml加载xml大文件 - 下部分

下载地址: RapidXml (sourceforge.net)https://rapidxml.sourceforge.net/ 将源码添加到自己的工程中 示例测试大文件耗时: 总共293w行数据,大概耗时不到1s。

将创建表字段语句快速转换成golang struct字段

用网页jquery快速生成 本地建立 struct.html <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>leo-转换</title> <script src"https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></s…

基于YOLOv7算法的高精度实时足球目标检测识别系统(PyTorch+Pyside6+YOLOv7)

摘要&#xff1a;基于YOLOv7算法的高精度实时足球目标检测系统可用于日常生活中检测与定位足球目标&#xff0c;此系统可完成对输入图片、视频、文件夹以及摄像头方式的目标检测与识别&#xff0c;同时本系统还支持检测结果可视化与导出。本系统采用YOLOv7目标检测算法来训练数…

scripty妙用

在monorepo项目中&#xff0c;随着子模块增多&#xff0c; 每个子项目都需要配置各自的package.json,并且大同小异&#xff0c;为了进一步提高配置效率&#xff0c;引入了scripty&#xff0c;自己写脚本&#xff0c;直接就可以用哦 1、安装 npm install scripty --save-dev 2…

【LeetCode刷题笔记(4)】【Python】【移动零】【简单】

文章目录 题目描述示例 1示例 2提示 解决方案题意拆解双指针算法双指针法的主要优点双指针法的使用场景举例&#xff1a; 解决方案&#xff1a;【双指针一次遍历】解题心得方案代码运行结果复杂度分析 结束语 移动零 题目描述 给定一个数组 nums&#xff0c;编写一个函数将所…

【Python】conda镜像配置,.condarc文件详解,channel镜像

1. conda 环境 安装miniconda即可&#xff0c;Miniconda 安装包可以到 http://mirrors.aliyun.com/anaconda/miniconda/ 下载。 .condarc是conda 应用程序的配置文件&#xff0c;在用户家目录&#xff08;windows&#xff1a;C:\users\username\&#xff09;&#xff0c;用于…

Peter算法小课堂—简单建模(2)

太戈编程736题 题目描述&#xff1a; 你是一只汪星人&#xff0c;地球毁灭后你回到了汪星&#xff0c;这里每天有n个小时&#xff0c;你需要为自己选择正好连续的m小时作为每天睡眠的时间。从凌晨开始&#xff0c;第i小时内的睡眠质量为xi&#xff0c;请问经过选择后&#xf…

WTF ‘Questions‘

WTF ‘Tech Team Lead’ As a Tech Team Lead, your role is to oversee the technical aspects of a project or team, and to provide guidance, support, and leadership to your team members. Here are some key responsibilities and aspects of the role: Leadership …

vite(一)——基本了解和依赖预构建

文章目录 一、什么是构建工具&#xff1f;1.为什么使用构建工具&#xff1f;2.构建工具的作用&#xff1f;3.构建工具怎么用&#xff1f; 二、经典面试题&#xff1a;webpack和vite的区别1.编译方式不同2.基础概念不同3.开发效率不同4.扩展性不同5.应用场景不同6.总结&#xff…

算法:最小生成树

文章目录 生成树Kruskal算法Prim算法 本篇总结的是最小生成树算法 生成树 连通图中的每一棵生成树&#xff0c;都是原图的一个极大无环子图&#xff0c;即&#xff1a;从其中删去任何一条边&#xff0c;生成树就不在连通&#xff1b;反之&#xff0c;在其中引入任何一条新边&…