重復次數是通過(guò)量詞指定的,可以緊跟在下面元素之后:
一般的重復量詞指定了一個(gè)最小數值和一個(gè)最大數值的匹配次數,
通過(guò)花括號包裹兩個(gè)數字,兩個(gè)數字之間用逗號隔開(kāi)的語(yǔ)法定義。
兩個(gè)數值都必須小于 65536, 并且第一個(gè)數字必須小于等于第二個(gè)。 比如:
z{2,4}
匹配 ”zz”, “zzz”, “zzzz”。 單個(gè)的右花括號不是特殊字符。
如果第二個(gè)數字被省略,但是逗號仍然存在,就代表沒(méi)有上限;
如果第二個(gè)數字和逗號都被省略,那么這個(gè)量詞就限定的是一個(gè)確定次數的匹配。
比如
[aeiou]{3,}
匹配至少三個(gè)連續的元音字母,但是同時(shí)也可以匹配更多,
而
\d{8}
則只能匹配 8 個(gè)數字。
左花括號出現在不允許使用量詞的位置或者與量詞語(yǔ)法不匹配時(shí),
被認為是一個(gè)普通字符,對它自身進(jìn)行原文匹配。 比如,{,6}就不是一個(gè)量詞,
會(huì )按照原文匹配四個(gè)字符 ”{,6}”。
量詞 {0} 是被授權的,它會(huì )導致的行為是認為前面的項和量詞不存在。
為了方便(以及歷史的兼容性),最常用的三個(gè)量詞都有單字符縮寫(xiě)。
* |
等價(jià)于 {0,} |
+ |
等價(jià)于 {1,} |
? |
等價(jià)于 {0,1} |
可以通過(guò)一個(gè)不匹配任何字符的子模式后面緊跟一個(gè)匹配 0 或多個(gè)字符的量詞
來(lái)構造一個(gè)沒(méi)有上限的無(wú)限循環(huán)。比如:
(a?)*
早期版本的 Perl 和 PCRE 對于這種模式會(huì )在編譯期得到一個(gè)錯誤。然而, 由于這在某些情況下是有用的,因此現在也接受這種模式了, 但是如果任何子模式的重復確實(shí)匹配不到任何字符,循環(huán)會(huì )被強制跳出。
默認情況下,量詞都是”貪婪”的,也就是說(shuō),
它們會(huì )在不導致模式匹配失敗的前提下,盡可能多的匹配字符(直到最大允許的匹配次數)。
這種問(wèn)題的典型示例就是嘗試匹配C語(yǔ)言的注釋。
出現在 /* 和 */ 之間的所有內容都被認為是注釋?zhuān)?在注釋中間,
可以允許出現單獨的 * 和 /。
對 C 注釋匹配的一個(gè)嘗試是使用模式
/\*.*\*/
,
假設將此模式應用在字符串 ”
/* first comment*/ not comment /*second
comment*/
”
它會(huì )匹配到錯誤的結果,也就是整個(gè)字符串,
這是因為量詞的貪婪性導致的,它會(huì )嘗試盡可能多的匹配字符。
然而,如果一個(gè)量詞緊跟著(zhù)一個(gè) ?(問(wèn)號) 標記,它就會(huì )成為懶惰(非貪婪)模式,
它不再盡可能多的匹配,而是盡可能少的匹配。
因此模式
/\*.*?\*/
在 C 的注釋匹配上將會(huì )正確的執行。
各個(gè)量詞自身的意義并不會(huì )改變,而是由于加入了 ? 使其首選的匹配次數發(fā)生改變。
不要將 ? 的這個(gè)用法和它作為量詞的用法混淆。因為它又兩種用法,
因此有時(shí)它會(huì )出現量詞,比如
\d??\d
會(huì )更傾向于匹配一個(gè)數字,
但同時(shí)如果為了達到整個(gè)模式匹配的目的,它也可以接受兩個(gè)數字的匹配。譯注:以模式 \w\d??\d\w 為例,對于字符串 ”a33a”,雖然 \d?? 是非貪婪的,
但由于如果使用貪婪會(huì )導致整個(gè)模式不匹配,所以,
最終它選擇的仍然是匹配到一個(gè)數字。
如果 PCRE_UNGREEDY 選項被設置(一個(gè)在 perl 中不可用的選項), 那么量詞默認情況下就是非貪婪的了。但是, 單個(gè)的量詞可以通過(guò)緊跟一個(gè) ? 來(lái)使其成為貪婪的。換句話(huà)說(shuō), PCRE_UNGREEDY 這個(gè)選項逆轉了貪婪的默認行為。
量詞后面緊跟一個(gè) ”+
” 是”占有”性。它會(huì )吃掉盡可能多的字符,
并且不關(guān)注后面的其他模式,比如 .*abc
匹配 ”aabc”,
但是 .*+abc
不會(huì )匹配,
因為 .*+
會(huì )吃掉整個(gè)字符串,從而導致后面剩余的模式得不到匹配。
可以使用占有符 (+) 修飾量詞來(lái)達到提升速度的目的。
當一個(gè)子組受最小數量大于 1 或有一個(gè)最大數量限制的量詞修飾時(shí), 按照最小或最大的數量的比例需要更多的存儲用于編譯模式。
如果一個(gè)模式以 .* 或 .{0,} 開(kāi)始并且 PCRE_DOTALL 選項開(kāi)啟(等價(jià)于 Perl 的 /s), 也就是允許 . 匹配換行符,那么模式會(huì )隱式的緊固,因為不管怎么樣, 接下來(lái)都會(huì )對目標字符串中的每個(gè)字符位置進(jìn)行嘗試,因此在第一次之后, 在任何位置都不會(huì )有一個(gè)對所有匹配重試的點(diǎn)。 PCRE 會(huì )想對待 \A 一樣處理這個(gè)模式。 在我們已知目標字符串沒(méi)有包含換行符的情況下, 當模式以 .* 開(kāi)始的時(shí)候我們?yōu)榱双@得這個(gè)優(yōu)化,值得設置 PCRE_DOTALL, 或者選擇使用 ^ 明確指明錨定。
譯注:這里的優(yōu)化指模式不匹配之后,不會(huì )回頭再來(lái)查找下一個(gè)位置, 比如沒(méi)有設置 PCRE_DOTALL,并且目標字符串第一個(gè)字符時(shí)換行符, 那么模式嘗試第一個(gè)字符,發(fā)現不匹配, 會(huì )重新用模式從第二個(gè)字符位置開(kāi)始進(jìn)行嘗試。 而使用了PCRE_DOTALL后, 是肯定匹配的….同理,當使用了 ^ 或者 /A的限定是,模式一旦不匹配,都可以直接退出, 而不用在目標字符串下一個(gè)位置再一次開(kāi)始整個(gè)模式的匹配。
當一個(gè)捕獲子組時(shí)重復的時(shí),捕獲到的該子組的結果是最后一次迭代捕獲的值。比如,
(tweedle[dume]{3}\s*)+
匹配字符串 ”tweedledum tweedledee”,
得到的的子組捕獲結果是 ”tweedledee”。然而,如果是嵌套的捕獲子組,
相應的捕獲值可能會(huì )被設置到之前的迭代中。
比如,
/(a|(b))+/
匹配字符串 ”aba”,
第二個(gè)捕獲子組得到的結果會(huì )是 ”b”。譯注:以例子說(shuō)明,
b 是第二個(gè)子組最后一次捕獲到的結果,所以, 第二個(gè)子組最后結果是 b,
這是符合”然而”之前描述的規則的。