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

正则表达式(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.hqwc.cn/news/256445.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GateWay网关介绍以及整合knife4j聚合所有服务的接口文档

为什么使用网关? 因为多个微服务的端口不同,前端调用不方便,使用网关可以统一接收处理前端的请求,同时方便接口的集中处理,比如鉴权、聚合接口文档、限流等等.. 这里使用Knife4j文档工具来实现接口文档:K…

Linux 防病毒软件:CentOS有哪些付费的防病毒软件

CentOS是一个基于开源的Linux发行版,通常不像Windows那样普遍需要使用付费的防病毒软件。大多数Linux系统侧重于使用开源和免费的安全工具来保护系统。一些常见的免费和开源的防病毒软件和安全工具包括ClamAV、Sophos Antivirus for Linux、rkhunter、chkrootkit等。 如果你非…

VMware提示:此虚拟机似乎正在使用中,取得该虚拟机的所有权失败错误的解决方案

当你遇到这个的时候是不是很疑惑,现在给你解决方案 step1: 先找到配置文件目录 D:\centOs7_mini\ 这里写成你的这个 step2: 在这个地方查找最后面是 .vmx.lck文件夹,然后进行修改、删除、移动都可以 step3: 去虚拟机那边重新启动就行

被法院判决赔偿316991元的【工务园】申请纳斯达克IPO上市

来源:猛兽财经 作者:猛兽财经 猛兽财经获悉,被法院判决赔偿316991元的人力资源SaaS平台Baiya International Group Inc(简称:工务园)近期已向美国证券交易委员会(SEC)提交招股书&am…

渗透测试——七、网站漏洞——命令注入和跨站请求伪造(CSRF)

渗透测试 一、命令注入二、跨站请求伪造(CSRF)三、命令注入页面之注人测试四、CSRF页面之请求伪造测试 一、命令注入 命令注入(命令执行) 漏洞是指在网页代码中有时需要调用一些执行系统命令的函数例如 system()、exec()、shell_exec()、eval()、passthru(),代码未…

JVM理解

1、JVM是什么? JVM是Java Virtual Machine(Java虚拟机)的缩写,由一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域等组成。 他是帮助我们将java代码 生成编译后 的 class 文件。 2、JRE、JDK和JVM 的关系 …

十六、FreeRTOS之FreeRTOS队列集

本节需要掌握以下内容: 1,队列集简介(了解) 2,队列集相关API函数介绍(熟悉) 3,队列集操作实验(掌握) 一、队列集简介(了解) 一个…

CopyOnWriteArraySet怎么用

简介 CopyOnWriteArraySet是一个线程安全的无序集合,它基于“写时复制”的思想实现。它继承自AbstractSet,可以将其理解成线程安全的HashSet。 CopyOnWriteArraySet在读取操作比较频繁、写入操作相对较少的情况下可以提高程序的性能和可靠性。它的线程…

java学习part40collections工具类

162-集合框架-Collections工具类的使用_哔哩哔哩_bilibili 1.collections工具类 感觉类似c的algorithm包,提供了很多集合的操作方法 2.排序 3.查找 4.复制替换 5.添加,同步

springboot 整合 Spring Security 中篇(RBAC权限控制)

1.先了解RBAC 是什么 RBAC(Role-Based Access control) ,也就是基于角色的权限分配解决方案 2.数据库读取用户信息和授权信息 1.上篇用户名好授权等信息都是从内存读取实际情况都是从数据库获取; 主要设计两个类 UserDetails和UserDetailsService 看下…

硬件基础:运放

理想运算放大器 理想运算放大器放大倍数无穷大;输入端阻抗无穷大,所以输入端电流为0;输出电压和负载无关,不管负载怎么变化,输出电压都是固定的。 还有个就是输出阻抗为0; 输出阻抗越小,输出时就…

12.Java程序设计-基于Springboot框架的Android学习生活交流APP设计与实现

摘要 移动应用在日常生活中扮演着越来越重要的角色,为用户提供了方便的学习和生活交流渠道。本研究旨在设计并实现一款基于Spring Boot框架的Android学习生活交流App,以促进用户之间的信息分享、学术交流和社交互动。 在需求分析阶段,我们明…