1.概述

捕获组捕获到的内容,不仅可以在正则表达式外部通过程序进行引用,也可以在正则表达式内部进行引用,这种引用方式就是反向引用。要了解反向引用,首先要了解捕获组,关于捕获组,参考 正则基础之——捕获组(capture group)。

反向引用的作用通常是用来查找或限定重复、查找或限定指定标识配对出现等等。

对于普通捕获组和命名捕获组的引用,语法如下:

普通捕获组反向引用:\k<number>,通常简写为\number

命名捕获组反向引用:\k<name>或者\k'name'

普通捕获组反向引用中number是十进制的数字,即捕获组的编号;命名捕获组反向引用中的name为命名捕获组的组名。

2.反向引用匹配原理

捕获组(Expression)在匹配成功时,会将子表达式匹配到的内容,保存到内存中一个以数字编号的组里,可以简单的认为是对一个局部变量进行了赋值,这时就可以通过反向引用方式,引用这个局部变量的值。一个捕获组(Expression)在匹配成功之前,它的内容可以是不确定的,一旦匹配成功,它的内容就确定了,反向引用的内容也就是确定的了。

反向引用必然要与捕获组一同使用的,如果没有捕获组,而使用了反向引用的语法,不同语言的处理方式不一致,有的语言会抛异常,有的语言会当作普通的转义处理。

3.举例说明一

源字符串:abcdebbcde

正则表达式:([ab])\1

对于正则表达式“([ab])\1”,捕获组中的子表达式“[ab]”虽然可以匹配“a”或者“b”,但是捕获组一旦匹配成功,反向引用的内容也就确定了。如果捕获组匹配到“a”,那么反向引用也就只能匹配“a”,同理,如果捕获组匹配到的是“b”,那么反向引用也就只能匹配“b”。由于后面反向引用“\1”的限制,要求必须是两个相同的字符,在这里也就是“aa”或者“bb”才能匹配成功。

考察一下这个正则表达式的匹配过程,在位置0处,由“([ab])”匹配“a”成功,将捕获的内容保存在编号为1的组中,然后把控制权交给“\1”,由于此时捕获组已记录了捕获内容为“a”,“\1”也就确定只有匹配到“a”才能匹配成功,这里显然不满足,“\1”匹配失败,由于没有可供回溯的状态,整个表达式在位置0处匹配失败。

正则引擎向前传动,在位置5之前,“([ab])”一直匹配失败。传动到位置5处时,,“([ab])”匹配到“b”,匹配成功,将捕获的内容保存在编号为1的组中,然后把控制权交给“\1”,由于此时捕获组已记录了捕获内容为“b”,“\1”也就确定只有匹配到“b”才能匹配成功,满足条件,“\1”匹配成功,整个表达式匹配成功,匹配结果为“bb”,匹配开始位置为5,结束位置为7。

扩展一下,正则表达式“([a-z])\1{2}”也就表达连续三个相同的小写字母,“([a-z])\1+”表示连续的n个相同的小写字母。

4.举例说明二

详细的分析讨论参考:正则表达式正向预搜索的问题。

源字符串:aaa bbbb ffffff 999999999

正则表达式:(\w)((?=\1\1\1)(\1))+

测试代码:

string test = "aaa bbbb ffffff 999999999";

Regex reg = new Regex(@"(\w)((?=\1\1\1)(\1))+");

MatchCollection mc = reg.Matches(test);

foreach (Match m in mc)

{

richTextBox2.Text += "匹配结果:" + m.Value.PadRight(12, ' ') + "匹配开始位置:" + m.Index + "\n";

}

//输出

匹配结果:bb          匹配开始位置:4

匹配结果:ffff        匹配开始位置:9

匹配结果:9999999     匹配开始位置:16

匹配结果分析:

正则表达式(\w)((?=\1\1\1)(\1))+从匹配结果上分析,其实就等价于 (\w)(\1)*(?=\1\1\1)(\1) ,这个会相对好理解一些,下面讨论下分析过程。

因为“+”等价于“{1,}”,表示至少匹配1次,下面把子表达式“((?=\1\1\1)(\1))+”展开来看下规律,下表中的“次数”表示子表达式“((?=\1\1\1)(\1))+”匹配成功的次数 。

次数

等价表达式

1

(\w)((?=\1\1\1)(\1))

2

(\w)((?=\1\1\1)(\1))((?=\1\1\1)(\1))

3

(\w)((?=\1\1\1)(\1))((?=\1\1\1)(\1))((?=\1\1\1)(\1))

如果最后一个“((?=\1\1\1)(\1))”匹配成功,那么中间的“((?=\1\1\1)(\1))”一定可以匹配成功,所以中间的限制条件(?=\1\1\1)就没有意义了,这时就可以简写为“(\1)”,也就是

次数

等价表达式

1

(\w)((?=\1\1\1)(\1))

2

(\w)(\1)((?=\1\1\1)(\1))

3

(\w)(\1)(\1)((?=\1\1\1)(\1))

可以归纳为等价于

(\w)(\1)*((?=\1\1\1)(\1))

因为“((?=\1\1\1)(\1))”开始和结尾的()原来是用作量词+修饰范围的,这里已经没有什么意义了,所以表达式最后可以归纳为等价于

(\w)(\1)*(?=\1\1\1)(\1)

分析这个表达式就容易多了。“(\w)”匹配一个字符,占一位,“\1”是对“\w”匹配内容的引用,“(\1)*”可以匹配0到无穷多个“(\w)”匹配到的字符,“(?=\1\1\1)(\1)”只占一位,但是“(?=\1\1\1)”要求所在位置右侧有三个连续相同的“(\w)”匹配到的字符,所以在“(?=\1\1\1)”这个位置右侧应该有三个字符,不过只有这个位置右侧的一个字符计入最后的匹配结果,最后两个只作为限制条件,不计入最后的匹配结果 。

以“999999999”为例,第一个“9”由“(\w)”匹配,第二到第六个“9”由“(\1)*”来匹配,第七个“9”由“(?=\1\1\1)(\1)”中最后的“(\1)”来匹配,而第七、八、九这三个“9”是用来保证满足“(?=\1\1\1)”这个条件的。

详细描述参考:正则基础之——反向引用

转载于:https://www.cnblogs.com/guorange/p/6693168.html

正则表达式之反向引用相关推荐

  1. Java正则表达式中的反向引用

    Java正则表达式中的反向引用是Java提供的另一个重要功能. 要了解反向引用 ,我们首先需要了解群组 . 正则表达式中的分组意味着将多个字符视为一个单元. 通过将要分组的字符放在一组括号" ...

  2. 正则表达式的捕获性分组/反向引用

    文章目录 分组 捕获性分组和反向引用 分组 正则的分组主要通过小括号来实现,括号包裹的子表达式作为一个分组,括号后可以紧跟限定词表示重复次数.如下,小括号内包裹的 abc 便是一个分组: // (ab ...

  3. 【C#进阶二】C#中的正则表达式知识总结(字符转义/字符类/ 定位点/ 分组构造 /数量词/反向引用构造/替换构造/替代/正则表达式选项)(理论篇)

    文章目录 0. 正则表达式网站推荐 1.字符转义 2.字符类 3. 定位点 4. 分组构造 5.数量词 6.反向引用构造 7.替换构造 8.替代 9.正则表达式选项 正则表达式是对字符串操作的一种逻辑 ...

  4. hive正则表达式反向引用

    反向引用 捕获会返回一个捕获组,这个分组是保存在内存中的,不仅可以在正则表达式外部通过程序进行引用,也可以在正则表达式内部进行引用,这种引用方式就是反向引用. 根据捕获组的命名规则,反向引用可分为: ...

  5. php 正则匹配反向引用,php正则表达式子模式的反向引用学习笔记

    需要用正则表达式获取字符串的标题.标题标签是h1~h6. 使用正则表达式:"@(.*?)@"或者'(.*?)@'.使用了@作为分隔符,注意单双引号的差别\\1与\1. 例1 代码如 ...

  6. java 正则 反向引用_正则之反向引用

    前言 某日在逛stackoverflow时,发现侧边栏的Hot Network Questions里有一例codegolf的问题Does it repeat?. 挑战 好奇之下点入观看,该题主的挑战如 ...

  7. php正则引用不能计算,php正则表达式 后向引用~

    php正则表达式 后向引用- 使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理.默认情况下,每个分组会自动拥有一个组号,规则是:从左 ...

  8. php 正则表达式 后向引用,php正则表达式 后向引用~ | 学步园

    php正则表达式 后向引用- 使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理.默认情况下,每个分组会自动拥有一个组号,规则是:从左 ...

  9. 正则基础之——反向引用

    From: http://blog.csdn.net/lxcnn/article/details/4476746 1        概述 捕获组捕获到的内容,不仅可以在正则表达式外部通过程序进行引用, ...

最新文章

  1. DataGrip 2019.2.5 —— MySQL数据表迁移到SQL Server数据表解决方案
  2. 单调栈之Next Greater Number
  3. 同一个页面多个按钮,根据按钮名字执行相应功能
  4. JWT:我应该使用哪种签名算法?
  5. 电子科技大学计算机读博好毕业,高产博士生读博一年达毕业要求:写论文不无聊...
  6. 阿里P8架构师谈:java架构师面试技能24全点
  7. python中自定义错误_Python中的自定义错误消息
  8. MASK LBP代币拍卖共募集近4000万美元
  9. firebug console说明
  10. CentOS7网络配置ping通外网
  11. Union和Union All ,
  12. Python学习笔记五
  13. 基于attention的seq2seq机器翻译实践详解
  14. 详细安装 kali 教程 和 基本命令使用
  15. 基于微信小程序的毕业设计题目(19)php菜谱美食小程序(含开题报告、任务书、中期报告、答辩PPT、论文模板)
  16. Arduino驱动315MHZ无线模块
  17. C语言练习题,从键盘输入一个字符,在给定的字符串中寻找该输入字符,若找到将该字符从字符串中删掉,并输出该字符串,没有找到给出提示信息“未找到”。
  18. 谈谈我在创业公司的感悟
  19. 从零开始学习oracle(2) oracle11g的远程链接和数据库调试
  20. JavaScript中获取键盘事件

热门文章

  1. xcode-select: error: tool 'xcodebuild' requires Xcode错误解决方法
  2. 父盒子高度为子盒子总高度自动撑满 height: fit-content; //设置内容高度
  3. 安卓USB开发教程 三 USB Accessory
  4. React开发(214):React中的Fragments
  5. 前端学习(2936):vue对象之间的操作
  6. [vue] 写出你知道的表单修饰符和事件修饰符
  7. [css] 请说说在什么时候用transition?什么时候使用animation?
  8. [vue] 从0到1自己构架一个vue项目,说说有哪些步骤、哪些重要插件、目录结构你会怎么组织
  9. 工作177:时间戳转换
  10. “约见”面试官系列之常见面试题第三十一篇之vue-router得守卫(建议收藏)