有時,我們想用正則匹配以某個子串開頭,且以某個子串或字符結(jié)尾的子字符串,但是結(jié)尾的字串或字符在原字符串中出現(xiàn)了多次,但我們只想匹配從開始處到第一次出現(xiàn)的地方,換句話說,想得到開始和結(jié)尾之間內(nèi)容最少的匹配。
通常使用如下字符類描述前導(dǎo)字符的重復(fù)特征:
1. ?: 告訴引擎匹配前導(dǎo)字符0次或一次。事實上是表示前導(dǎo)字符是可選的。
2. +: 告訴引擎匹配前導(dǎo)字符1次或多次。
3. *: 告訴引擎匹配前導(dǎo)字符0次或多次。
4. {min, max}: 告訴引擎匹配前導(dǎo)字符min次到max次。min和max都是非負(fù)整數(shù)。如果有逗號而max被省略了,則表示max沒有限制;如果逗號和max都被省略了,則表示重復(fù)min次。
因此 {0,} 和 * 一樣,{1,} 和 + 的作用一樣。
默認(rèn)情況下,? + * {min, max}都是貪婪的,也就是說,它會根據(jù)前導(dǎo)字符去匹配盡可能多的內(nèi)容。
非貪婪就是匹配盡可能少的內(nèi)容。
結(jié)合實例來分析哈基于正則的引擎對文本的匹配過程。原始字符串:This is a <EM>first</EM> test
,使用正則<.+>來匹配HTML標(biāo)簽,期望第一次匹配得到<EM>
,第二次匹配得到</EM>
,實際卻是第一次匹配就得到了<EM>first</EM>
。
來看看匹配過程,第一個記號是<
,這是一個文本字符,匹配其自身。第二個符號是.
,匹配了字符E
,然后+
一直可以匹配其余的字符,直到一行的結(jié)束。然后到了換行符,匹配失?。?strong>.
不匹配換行符)。于是引擎開始對下一個正則表達(dá)式符號進(jìn)行匹配,即試圖匹配>
。到目前為止,<.+
已經(jīng)匹配了<EM>first</EM> test
。引擎會試圖將>
與換行符進(jìn)行匹配,結(jié)果失敗了。于是引擎進(jìn)行回溯?;厮莺蟮钠ヅ錉顩r是 <.+
匹配 <EM>first</EM> tes
。于是引擎將>
與t
進(jìn)行匹配。顯然還是會失敗。這個過程繼續(xù),直到 <.+
匹配 <EM>first</EM
,>
與>
匹配。于是引擎找到了一個匹配<EM>first</EM>
。記住,正則導(dǎo)向的引擎是急切的,所以它會急著報告它找到的第一個匹配。而不是繼續(xù)回溯,即使可能會有更好的匹配,例如<EM>
。所以我們可以看到,由于+
的貪婪性,使得正則表達(dá)式引擎返回了一個最左邊的最長的匹配。
如果想得到期望的結(jié)果,就需要啟用非貪婪模式:<.+?>
總結(jié):如果是貪婪匹配模式,正則引擎會一直匹配到字符串最后;當(dāng)匹配為false時,就回溯以找到倒數(shù)第一個匹配位置,返回匹配結(jié)果。 如果是非貪婪匹配模式,正則引擎會匹配到符合pattern的末尾位置那個字符,然后再往后走一步,發(fā)現(xiàn)匹配為false時,就回溯以找到最近一個匹配為true的位置,返回匹配結(jié)果。
例如,原始字符串:
{"accesskey":{"acccessKeyId":"XhUURxsMlJE6EiXf","accessKeySecret":"Q9fMpgBgRnKycMRD28MMkkFMbiNkbY"},"dbGrant":{"0000031736":"READWRITE"},"dbSchemaId":"0000031737"}
現(xiàn)在想把這部分敏感信息替換為空字符串:
"accesskey":{"acccessKeyId":"XhUURxsMlJE6EiXf","accessKeySecret":"Q9fMpgBgRnKycMRD28MMkkFMbiNkbY"},
先不考慮結(jié)尾的逗號,嘗試正則:"accesskey":\{.+\},直接匹配至原始字符串結(jié)尾的}字符,因為引擎默認(rèn)會匹配盡可能多的內(nèi)容。
考慮到貪婪性,將正則修改為:"accesskey":\{.+\}+?,匹配結(jié)果一樣。納尼?難道我對貪婪性的理解有問題。梳理哈使用姿勢,我期望它匹配到開始位置之后出現(xiàn)的第一個}字符,對應(yīng)的表達(dá)式部分為\}+?。套用非貪婪模式分析問題,期望對一個或多個}字符進(jìn)行匹配,且匹配盡可能少的內(nèi)容,但在原始串中,}字符都是分開的,沒有連續(xù),無論如何只能匹配一個單獨的}字符??梢妼字符開啟非貪婪模式匹配行不通。
想要匹配到開始位置之后出現(xiàn)的第一個}字符 也可以表達(dá)為 開始位置和末尾}字符之間的內(nèi)容最少,對應(yīng)正則部分修改為:.+?,完整表達(dá)式:"accesskey":\{.+?\},測試匹配結(jié)果,妥妥的。
正確理解正則回溯
深入淺出之正則(一)
正則進(jìn)階(二)- 回溯引用、前后查找、嵌入條件
正則學(xué)習(xí)筆記(6)向前查找和向后查找
正則 - 向前匹配、向后匹配、負(fù)向前匹配、負(fù)向后匹配