正则表达式 - 贪婪与非贪婪(惰性)

使用场景

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

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

一般使用以下字符类描述前导字符的重复特征:
1. ?: 告诉引擎匹配前导字符0次或一次。事实上是表示前导字符是可选的。
2. +: 告诉引擎匹配前导字符1次或屡次。
3. *: 告诉引擎匹配前导字符0次或屡次。
4. {min, max}: 告诉引擎匹配前导字符min次到max次。min和max都是非负整数。若是有逗号而max被省略了,则表示max没有限制;若是逗号和max都被省略了,则表示重复min次。
所以 {0,} 和 * 同样,{1,} 和 + 的做用同样。正则表达式

贪婪

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

非贪婪(惰性)

非贪婪就是匹配尽量少的内容。测试

原理浅析

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

来看看匹配过程,第一个记号是<,这是一个文本字符,匹配其自身。第二个符号是.,匹配了字符E,而后+一直能够匹配其他的字符,直到一行的结束。而后到了换行符,匹配失败(.不匹配换行符)。因而引擎开始对下一个正则表达式符号进行匹配,即试图匹配>。到目前为止,<.+已经匹配了<EM>first</EM> test。引擎会试图将>与换行符进行匹配,结果失败了。因而引擎进行回溯。回溯后的匹配情况是 <.+ 匹配 <EM>first</EM> tes。因而引擎将>t进行匹配。显然仍是会失败。这个过程继续,直到 <.+ 匹配 <EM>first</EM>>匹配。因而引擎找到了一个匹配<EM>first</EM>。记住,正则导向的引擎是急切的,因此它会急着报告它找到的第一个匹配。而不是继续回溯,即便可能会有更好的匹配,例如<EM>。因此咱们能够看到,因为+的贪婪性,使得正则表达式引擎返回了一个最左边的最长的匹配。code

若是想获得指望的结果,就须要启用非贪婪模式:<.+?>htm

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

实例

例如,原始字符串:资源

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

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

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

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

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

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

参考资源

正确理解正则回溯
深刻浅出之正则(一)
正则进阶(二)- 回溯引用、先后查找、嵌入条件
正则学习笔记(6)向前查找和向后查找
正则 - 向前匹配、向后匹配、负向前匹配、负向后匹配

相关文章
相关标签/搜索