使用场景

有时,我们想用正则匹配以某个子串开头,且以某个子串或字符结尾的子字符串,但是结尾的字串或字符在原字符串中出现了多次,但我们只想匹配从开始处到第一次出现的地方,换句话说,想得到开始和结尾之间内容最少的匹配。

正则的贪婪与非贪婪(惰性)

通常使用如下字符类描述前导字符的重复特征:

1. ?: 告诉引擎匹配前导字符0次或一次。事实上是表示前导字符是可选的。

2. +: 告诉引擎匹配前导字符1次或多次。

3. *: 告诉引擎匹配前导字符0次或多次。

4. {min, max}: 告诉引擎匹配前导字符min次到max次。min和max都是非负整数。如果有逗号而max被省略了,则表示max没有限制;如果逗号和max都被省略了,则表示重复min次。

因此 {0,} 和 * 一样,{1,} 和 + 的作用一样。

贪婪

默认情况下,? + * {min, max}都是贪婪的,也就是说,它会根据前导字符去匹配尽可能多的内容。

非贪婪(惰性)

非贪婪就是匹配尽可能少的内容。

原理浅析

结合实例来分析哈基于正则的引擎对文本的匹配过程。原始字符串:This is a first test,使用正则<.>来匹配HTML标签,期望第一次匹配得到,第二次匹配得到,实际却是第一次匹配就得到了first

来看看匹配过程,第一个记号是。到目前为止,<.>first test。引擎会试图将>与换行符进行匹配,结果失败了。于是引擎进行回溯。回溯后的匹配状况是 <.>first tes。于是引擎将>与t进行匹配。显然还是会失败。这个过程继续,直到 <.>first与>匹配。于是引擎找到了一个匹配first。记住,正则导向的引擎是急切的,所以它会急着报告它找到的第一个匹配。而不是继续回溯,即使可能会有更好的匹配,例如。所以我们可以看到,由于+的贪婪性,使得正则表达式引擎返回了一个最左边的最长的匹配。

如果想得到期望的结果,就需要启用非贪婪模式:<.>

总结:如果是贪婪匹配模式,正则引擎会一直匹配到字符串最后;当匹配为false时,就回溯以找到倒数第一个匹配位置,返回匹配结果。 如果是非贪婪匹配模式,正则引擎会匹配到符合pattern的末尾位置那个字符,然后再往后走一步,发现匹配为false时,就回溯以找到最近一个匹配为true的位置,返回匹配结果。

实例

例如,原始字符串:

{"accesskey":{"acccessKeyId":"XhUURxsMlJE6EiXf","accessKeySecret":"Q9fMpgBgRnKycMRD28MMkkFMbiNkbY"},"dbGrant":{"0000031736":"READWRITE"},"dbSchemaId":"0000031737"}

现在想把这部分敏感信息替换为空字符串:

"accesskey":{"acccessKeyId":"XhUURxsMlJE6EiXf","accessKeySecret":"Q9fMpgBgRnKycMRD28MMkkFMbiNkbY"},

先不考虑结尾的逗号,尝试正则:"accesskey":\{.+\},直接匹配至原始字符串结尾的}字符,因为引擎默认会匹配尽可能多的内容。

考虑到贪婪性,将正则修改为:"accesskey":\{.+\}+?,匹配结果一样。纳尼?难道我对贪婪性的理解有问题。梳理哈使用姿势,我期望它匹配到开始位置之后出现的第一个}字符,对应的表达式部分为\}+?。套用非贪婪模式分析问题,期望对一个或多个}字符进行匹配,且匹配尽可能少的内容,但在原始串中,}字符都是分开的,没有连续,无论如何只能匹配一个单独的}字符。可见对}字符开启非贪婪模式匹配行不通。

想要匹配到开始位置之后出现的第一个}字符 也可以表达为 开始位置和末尾}字符之间的内容最少,对应正则部分修改为:.+?,完整表达式:"accesskey":\{.+?\},测试匹配结果,妥妥的。

参考资源

java 正则 惰性匹配_正则表达式 - 贪婪与非贪婪(惰性)相关推荐

  1. java正则全局匹配_正则表达式全局匹配模式(g修饰符)

    正则表达式g修饰符: g修饰符用语规定正则表达式执行全局匹配,也就是在找到第一个匹配之后仍然会继续查找. 语法结构: 构造函数方式: new RegExp("regexp",&qu ...

  2. java 正则最小匹配_正则表达式实现最小匹配功能的方法

    本文实例讲述了正则表达式实现最小匹配功能的方法.分享给大家供大家参考,具体如下: 正则表达式默认情况下实现的是最大化匹配,这在有些情况下是非常不愿意出现的,比如下面这段代码: # starting I ...

  3. java正则任意字符_正则表达式匹配任意字符(包括换行符)的写法

    今天在Java中想使用正则表达式来获取一段文本中的任意字符.于是很随意得就写出如下匹配规则: (.*) 结果运行之后才发现,无法获得换行之后的文本.于是查了一下手册,才发现正则表达式中,". ...

  4. java 正则 单个字符_正则表达式教程之匹配单个字符详解

    本文实例讲述了正则表达式教程之匹配单个字符.分享给大家供大家参考,具体如下: 注:在所有例子中正则表达式匹配结果包含在源文本中的[和]之间,有的例子会使用Java来实现,如果是java本身正则表达式的 ...

  5. java正则出现次数_正则表达式(二)—匹配次数的正则

    正则表达式 匹配次数的正则 在前一篇文章中,我们总结了和位置相关的正则,在这篇文章中,我们将继续学习正则表达式其它的内容. 假如现在给你一个regular_1.txt文件,让你找出含有连续2个a的行, ...

  6. java 正则 括号外_正则表达式匹配括号外的符号及数据

    正则表达式匹配括号外的符号 [\\?!/\\.,\\s]+(?=[^\\)]*(\\(|$)) 将括号外的?!/.,和空格(连续多个时同时)匹配 如 String string1 = "sd ...

  7. java正则表达 替换_正则表达式 replace()替换

    标签: 定义和用法 replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串. 语法 stringObject.replace(regexp,replaceme ...

  8. java 正则 预编译_正则表达式预编译功能的正确使用

    在使用正则表达式时,利用好其预编译功能,可以有效加快正则匹配速度. 同时,Pattern要定义为static final静态变量,以避免执行多次预编译. 下面,我们列举两类使用正则的场景,来具体说明预 ...

  9. java 正则 工具类_正则表达式工具类,正则表达式封装,Java正则表达式

    正则表达式工具类 正则表达式封装 Java正则表达式 >>>>>>>>>>>>>>>>>>& ...

最新文章

  1. Python学习笔记二:布尔表达式
  2. SpringBoot复习:4(@ImportResource)
  3. 来吧!我教你画真正的流程图
  4. 基于ECI+FaaS构建游戏战斗结算服最佳实践
  5. Android——Fragment介绍
  6. Windows如何上传代码到Github
  7. UML类图关系表示方法
  8. STM32H743+CubeMX-使用ADC(16bit分辨率)模数转换器读取CPU的温度(串行方式)
  9. 大数据学习笔记06:伪分布式Hadoop
  10. Code Access Security (CAS)
  11. grub rescue修复
  12. 6-3 图片合成视频
  13. 为什么仿宋字体打印出楷体_请问仿宋体和楷体有什么区别?
  14. 《论文阅读》D3DLO: DEEP 3D LIDAR ODOMETRY
  15. 计算机环境变量怎么恢复默认,环境变量怎么还原
  16. java 比较日期大小(方法之一compare to 备忘)
  17. [Filco]蓝牙连接键盘
  18. 笔记|matplotlib 技巧|使用 gricspec 实现的不同大小子图
  19. 管理 POP3 和 IMAP4 服务
  20. Linux防火墙firewall只允许特定IP访问

热门文章

  1. RDS查看Binlog日志内容
  2. 世纪华通与华为签署合作协议,加快推进绿色数据中心建设
  3. 苹果将明年上半年iPhone出货量目标提高 30%
  4. iPhone 13拍照马赛克、换屏无法解锁Face ID、iPad mini 6“果冻屏”:等“百香果”吧...
  5. 为了进大厂,我所经历的奇葩面试
  6. 永辉生活APP卖茅台只收款不发货,永辉超市回应...
  7. 拼多多市值超2100亿美元 黄峥成中国第二大富豪
  8. 覆盖7大手机品牌近4亿安卓用户 “互传联盟”让分享更容易
  9. iPhone 12或支持全新短距离WiFi标准 数据传输更快
  10. 有没有跟新型肺炎确诊患者同乘车?百度可查!