首頁  >  文章  >  後端開發  >  php—PCRE正規表示式重複/量詞

php—PCRE正規表示式重複/量詞

伊谢尔伦
伊谢尔伦原創
2016-11-21 17:18:221229瀏覽

重複次數是透過量詞指定的,可以緊跟在下面元素之後:

單獨的字符, 可以是經過轉義的

元字符。

字符類

後向引用(參加下一部分)

子組(除非它是一個斷言)

一般的重複量詞指定了一個最小數值和一個最大數值的匹配次數, 透過花括號包裹兩個數字,兩個數字之間用逗號隔開的語法定義。 兩個數值都必須小於 65536, 且第一個數字必須小於等於第二個。 例如: z{2,4} 匹配 ”zz”, “zzz”, “zzzz”。 單一的右花括號不是特殊字元。 如果第二個數字被省略,但是逗號仍然存在,就代表沒有上限; 如果第二個數字和逗號都被省略,那麼這個量詞就限定的是一個確定次數的匹配。 例如 [aeiou]{3,} 配對至少三個連續的元音字母,但是同時也可以配對更多, 而 d{8} 則只能符合 8 個數字。 左花括號出現在不允許使用量詞的位置或與量詞語法不符時, 被認為是一個普通字符,對它本身進行原文匹配。 例如,{,6}就不是一個量詞, 會依照原文配對四個字元 ”{,6}”。

量詞 {0} 是被授權的,它會導致的行為是認為前面的項和量詞不存在。

為了方便(以及歷史的兼容性),最常用的三個量詞都有單字元縮寫。

單字量詞

*    等價於 {0,}    

+    等價於 {1,}    緊跟著一個符合0 或多個字元的量詞來建構一個沒有上限的無限循環。 例如:(a?)*

早期版本的 perl 和 pcre 對於這種模式會在編譯期間得到一個錯誤。然而, 由於這在某些情況下是有用的,因此現在也接受這種模式了, 但是如果任何子模式的重複確實匹配不到任何字符,循環會被強制跳出。

預設情況下,量詞都是」貪婪」的,也就是說, 它們會在不導致模式匹配失敗的前提下,盡可能多的匹配字元(直到最大允許的匹配次數)。 這種問題的典型範例就是嘗試匹配C語言的註解。 出現在 /* 和 */ 之間的所有內容都被視為註釋, 在註釋中間, 可以允許出現單獨的 * 和 /。 對C註解匹配的一個嘗試是使用模式 /*.**/, 假設將此模式應用在字串”/* first comment*/ not comment /*second comment*/” 它會匹配到錯誤的結果,也就是整個字串, 這是因為量詞的貪婪性導致的,它會嘗試盡可能多的匹配字元。

然而,如果一個量詞緊跟著一個 ?(問號) 標記,它就會成為懶惰(非貪婪)模式, 它不再盡可能多的匹配,而是盡可能少的匹配。 因此模式 /*.*?*/ 在 C 的註解匹配上將會正確的執行。 各個量詞本身的意義並不會改變,而是由於加入了 ? 使其首選的匹配次數發生改變。 不要將 ? 的這個用法和它當作量詞的用法混淆。因為它又兩種用法, 因此有時它會出現量詞,例如 d??d 會更傾向於匹配一個數字, 但同時如果為了達到整個模式匹配的目的,它也可以接受兩個數字的匹配。譯註: 以模式wd??dw 為例,對於字符串”a33a”,雖然d?? 是非貪婪的, 但由於如果使用貪婪會導致整個模式不匹配,所以, 最終它選擇的仍然是匹配到一個數字。

如果 PCRE_UNGREEDY 選項被設定(一個在 perl 中不可用的選項), 那麼量詞預設情況下就是非貪婪的了。但是, 單一的量詞可以透過緊跟一個 ? 來使其成為貪婪的。換句話說, PCRE_UNGREEDY 這個選項逆轉了貪婪的預設行為。

量詞後面緊跟著一個 ”+” 是」佔有」性。它會吃掉盡可能多的字符, 並且不關注後面的其他模式,比如 .*abc 匹配”aabc”, 但是 .*+abc 不會匹配, 因為 .*+ 會吃掉整個字符串,從而導致後面剩餘的模式無法匹配。 自PHP 4.3.3 起, 可使用佔有符號 (+) 修飾量詞來達到提升速度的目的。

當一個子組受最小數量大於 1 或有一個最大數量限制的量詞修飾時, 按照最小或最大的數量的比例需要更多的存儲用於編譯模式。

如果一個模式以.* 或.{0,} 開始並且 PCRE_DOTALL 選項開啟(等價於perl 的/s), 也就是允許.匹配換行符,那麼模式會隱式的緊固,因為不管怎麼樣,接下來都會對目標字串中的每個字元位置進行嘗試,因此在第一次之後, 在任何位置都不會有一個對所有匹配重試的點。 PCRE 會想對 A 一樣處理這個模式。 在我們已知目標字串沒有包含換行符的情況下, 當模式以 .* 開始的時候我們為了獲得這個優化,值得設定 PCRE_DOTALL, 或選擇使用 ^ 明確指明錨定。

譯註:這裡的優化指模式不匹配之後,不會回頭再來查找下一個位置, 例如沒有設定PCRE_DOTALL,並且目標字符串第一個字符時換行符, 那麼模式嘗試第一個字符,發現不匹配, 會重新用模式從第二個字元位置開始進行嘗試。 而使用了PCRE_DOTALL後, 是肯定匹配的….同理,當使用了^ 或/A的限定是,模式一旦不匹配,都可以直接退出, 而不用在目標字符串下一個位置再一次開始整個模式的匹配。

當一個捕獲子組時重複的時,捕獲到的該子組的結果是最後一次迭代捕獲的值。例如, (tweedle[dume]{3}s*)+匹配字串 ”tweedledum tweedledee”, 得到的的子組捕獲結果是 ”tweedledee”。然而,如果是嵌套的捕獲子組, 對應的捕獲值可能會被設定到先前的迭代中。例如,/(a|(b))+/ 匹配字串 ”aba”, 第二個捕獲子組得到的結果會是 ”b”。譯註:不理解然而之後的部分,以例子說明, b 是第二個子組最後一次捕獲到的結果,所以, 第二個子組最後結果是 b, 這是符合”然而”之前描述的規則的。


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn