固化分组,又叫原子组。

语法格式:(?>…)

我们在使用非贪婪模式时,匹配过程中可能会进行多次的回溯,回溯越多,正则表达式的运行效率就越低。而固化分组就是用来减少回溯次数的。

实际上,固化分组 (?>…) 的匹配与正常的匹配并无分别,它并不会改变匹配结果。唯一的不同就是:固化分组匹配结束时,它匹配到的文本已经固化为一个单元,只能作为整体而保留或放弃,小括号内的子表达式中未使用的备用状态都会被放弃,所以回溯永远也不能选择其中的状态(因此不能参与回溯)。

javaScriptjavapython 中并不支持固化分组的语法。不过,它在 php.NET 中表现良好。

下面我们通过一个 php 的固化分组正则表达式例子来深入地理解固化分组:

假如要处理一批数据,原格式为 123.456, 因为浮点数显示问题,部分数据格式会变为 123.456000000789 这种, 现要求只保留小数点后 2~3 位,但是最后一位不能为 0,那么这个正则怎么写呢?

$str = "123.456000000789";
echo preg_replace("/(\.\d\d[1-9]?)\d*/","\\1",$str); // 123.456

以上的正则表达式,对于 123.456 这种格式的数据,将白白处理一遍,为了提高效率,我们应该将 123.456 排除在外,我们将量词 * 改成 +。如下所示:

$str = "123.456";
echo preg_replace("/(\.\d\d[1-9]?)\d+/","\\1",$str);

(.\d\d[1-9]?) 会正常匹配到 .456,而 \d+ 表示匹配大于等于 1 个由 0-9 的任意数字组成的字符串,即匹配至少一个任意数字,所以 \d+ 匹配到 6 后面的结尾处位置时,会匹配失败,然后会要求 [1-9]? 回溯到备选状态,也就是放弃匹配数字 6,让给 \d+ 去匹配,结果匹配成功,最后整个正则式匹配到字符串 .456,(.\d\d[1-9]?) 匹配到 .45,\d+ 匹配到 6,所以 \1 引用到的是 .45,也就是把源字符串 123.456,后面的 .456 替换成了 .45,本来保留小数点后 3 位是符合需求的,现在反而被处理成了 .45,显然 123.45 不是我们期望的匹配结果,那我们应该怎么做呢?能否让 [1-9]? 一旦匹配成功,便不再进行回溯,这里就要用到固化分组,如下所示:

$str = "123.456";
echo preg_replace("/(\.\d\d(?>[1-9]?))\d+/","\\1",$str);

(?>[1-9]?) 就是固化分组,(?>[1-9]?) 成功匹配了 6,因为 (?>[1-9]?) 是固化分组,所以 ? 产生的备选状态被放弃,此时固化分组匹配到的 6 便不能用于正则引擎的回溯。子表达式 \d+ 匹配失败,尝试回溯也失败,导致整个正则表达式第 1 次迭代匹配失败,后面会继续迭代匹配到源字符串的结尾处,最后正则引擎才停止服务,不过后面的几次迭代匹配也都是失败的,那么最终的结果就是,正则表达式没有匹配到任何东西,替换动作也没有执行,这符合我们的需求。

php 还提供了占有优先的语法,效果和固化分组一样:

$str = "123.456";
echo preg_replace("/(\.\d\d[1-9]?+)\d+/","\\1",$str);

在量词 ? 后面加个 +,就变成了占有优先量词,意为着 [1-9]?+ 匹配到 6 后,是没有备选状态的(即无法回溯),这样 \d+ 最后匹配失败,最终导致整个匹配过程失败,没有匹配到任何东西。

虽然 java 不支持固化分组的语法,但 java 也提供了占有优先的语法,同样能够避免正则回溯。如下:

String str = "123.456";
System.out.println(str.replaceAll("(\\.\\d\\d[1-9]?+)\\d+", "$1"));// 123.456

值得注意的是:java 中 replaceAll 方法需要双反斜杠 \\作为转义符号。

正则表达式的固化分组相关推荐

  1. Python正则表达式: 元字符/转义/分组/匹配原则/re模块属性方法大全

    正则表达式 动机 文本处理已经成为计算机常见工作之一 对文本内容的搜索,定位,提取是逻辑比较复杂的工作 为了快速方便的解决上述问题,产生了正则表达式技术 简介 定义 即文本的高级匹配模式,提供搜索,替 ...

  2. 十分钟掌握正则表达式!4_分组匹配_捕获形分组

    javascript正则表达式 1.分组 1.1.候选:一个分组中,可以有多个候选表达式,用|分隔: 1.2.捕获与引用: 1.2.1 与replace配合: 1.2.2 给replace传迭代函数, ...

  3. JAVA正则表达式高级用法(分组与捕获)

    2019独角兽企业重金招聘Python工程师标准>>> 正则表达式在字符串处理中经常使用,关于正则简单的用法相信有一点程序基础的人都懂得一些,这里就不介绍简单基础了.这里主要讲解一下 ...

  4. list 分组_「正则表达式」 匹配分组

    1. 匹配分组相关正则表达式 代码功能|匹配左右任意一个表达式(ab)将括号中字符作为一个分组um引用分组num匹配到的字符串(?P)分组起别名(?P=name)引用别名为name分组匹配到的字符串 ...

  5. mysql 正则匹配 捕获组_常用正则表达式 捕获组(分组)

    1.img标签 //,空格后src以'或"开始..... Regex reg = new Regex("]*\\ssrc=(['\"]+[^<>'\" ...

  6. 正则表达式 - 选择、分组和向后引用

    目录 一.选择操作 1. 选项和修饰符 2. 统计单词出现的行数 二.子模式 三.捕获分组和后向引用 命名分组 四.非捕获分组 1. 原子分组 2. 回溯 (1)量词导致回溯 (2)分支导致回溯 (3 ...

  7. 正则表达式中的分组的匹配次数的理解

    正则表达式:/((\d){1,6})+/ 这个正则表达式可以匹配任意数量的数字. 限定符 + 指的是前面的子表达式 (\d){1,6} 可以出现 1 次或者多次,所以如果是贪婪匹配,每次迭代匹配的数字 ...

  8. 正则表达式的命名分组

    语法格式:(?<name>-) 命名分组也是捕获性分组,它将匹配的字符串捕获到一个组名称或编号名称中,在获得匹配结果后,可通过分组名进行获取. 如下是一个python的命名分组的例子: i ...

  9. [Regular] 2、正则表达式基础元字符及分组、捕获

          分组.捕获.分组不捕获       普通的无特殊意义的括号通常有两种功能:分组和捕获.       捕获型括号的编号是按照括号出现的次序,从左到右计算的.如果提供反向引用,可以在表达式的后 ...

最新文章

  1. MySQL案例-多源复制引起的内存泄漏
  2. 160个Crackme027之First CD-Check
  3. OpenGL相机控制之一
  4. .NET Core项目从xproj+project.json向csproj迁移简介
  5. POJ2251Dungeon Master
  6. 整型数据类型java_Java 六种基本整型数据类型变量的取值范围
  7. Vue (响应式原理-模拟-3-Compiler)
  8. 用正则表达式抽取文本
  9. jpushinterface.setalias的几个参数都是啥意思_很多电工老师傅都不知道,低压断路器基本参数,你懂几个?...
  10. Security+ 学习笔记5 常见的网络攻击
  11. python移动文件(非文件夹)
  12. 如何学习摸具设计?怎样学习摸具设计?学习摸具设计的方法。
  13. app源码 官府菜.cn_坑死的天牛淘客APP
  14. 【LaTex】各种空格的实现(相对quad、qquad、\,、\:、\;、\!、endspace、thinspace、negthinspace绝对vspace和hspace膨胀hfill、vfill)
  15. android jcenter google 镜像
  16. 关于win10笔记本电脑插入耳机后依旧外放的问题(亲测戴尔)
  17. 雪花算法中机器id保证全局唯一
  18. 【微机原理作业】8086存储器读写实验
  19. 【元宵快乐】猜灯谜吃元宵 元气满满闹元宵~(附猜灯谜小游戏)
  20. 成都最最最牛逼的IT公司全在这了,来成都一起造富。。。

热门文章

  1. istio api_Istio的网络API解释了
  2. jvm体系结构概述_JVM体系结构:JVM和JVM体系结构概述
  3. 来的多可选_您的框架有多可扩展性?
  4. java 开发:md5_Java社区调查结果:74%的开发人员希望减少详细程度
  5. java 编译 器 ide_在没有IDE的情况下编译和运行Java
  6. spring发邮件_跟踪异常–第4部分– Spring的邮件发件人
  7. junit测试设置不回滚_正确设置JUnit测试名称
  8. 从外部CorDapp扩展和覆盖流
  9. 使用AWS Lambdas扩展技术堆栈
  10. xml对象映射_将对象映射到多个XML模式–天气示例