正則表達式 - 貪婪與非貪婪(惰性)

使用場景

有時,咱們想用正則匹配以某個子串開頭,且以某個子串或字符結尾的子字符串,可是結尾的字串或字符在原字符串中出現了屢次,但咱們只想匹配從開始處到第一次出現的地方,換句話說,想獲得開始和結尾之間內容最少的匹配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)向前查找和向後查找
正則 - 向前匹配、向後匹配、負向前匹配、負向後匹配

相關文章
相關標籤/搜索