2024 日本 PHP 研討會

重複

重複是由量詞指定的,量詞可以跟在以下任何項目之後

  • 單個字元,可能已跳脫
  • . 元字元
  • 字元類別
  • 反向參考(請參閱下一節)
  • 括號括起來的子模式(除非它是斷言 - 請參閱下文)

一般重複次數量詞透過在大括號 {} 內以逗號分隔的兩個數字來指定允許匹配的最小和最大次數。這些數字必須小於 65536,且第一個數字必須小於或等於第二個數字。例如:z{2,4} 匹配「zz」、「zzz」或「zzzz」。單獨的右大括號本身並不是特殊字元。如果省略第二個數字但存在逗號,則沒有上限;如果第二個數字和逗號都省略,則量詞指定所需匹配的確切次數。因此,[aeiou]{3,} 匹配至少 3 個連續的母音,但也可能匹配更多;而 \d{8} 匹配正好 8 個數字。

在 PHP 8.4.0 之前,如果左大括號出現在不允許使用量詞的位置,或者不符合量詞語法的左大括號,會被視為字面字元。例如,{,6} 不是量詞,而是由四個字元組成的字面字串。從 PHP 8.4.0 開始,PCRE 擴充套件捆綁了 PCRE2 10.44 版,允許使用 \d{,8} 等模式,它們會被解釋為 \d{0,8}。此外,從 PHP 8.4.0 開始,允許在量詞周圍使用空格,例如 \d{0 , 8}\d{ 0 , 8 }

允許使用量詞 {0},這會使表達式表現得如同前一個項目和量詞不存在一樣。

為了方便起見(以及歷史相容性),三個最常用的量詞具有單字元縮寫:

單字元量詞
* 等價於 {0,}
+ 等價於 {1,}
? 等價於 {0,1}

有可能透過在一個可以匹配零個字元的子模式後加上一個沒有上限的量詞來構造無限迴圈,例如:(a?)*

早期版本的 Perl 和 PCRE 會在編譯時針對此類模式發出錯誤。然而,由於有些情況下這可能很有用,現在接受此類模式,但如果子模式的任何重複實際上匹配零個字元,則會強制中斷迴圈。

預設情況下,量詞是「貪婪的」,也就是說,它們會盡可能多地匹配(最多達到允許的最大次數),而不會導致模式的其餘部分匹配失敗。一個典型的例子是在嘗試匹配 C 程式中的註釋時會出現問題。註釋出現在 /* 和 */ 序列之間,並且在序列中,可能會出現單個 * 和 / 字元。嘗試透過將模式 /\*.*\*/ 應用於字串 /* first comment */ not comment /* second comment */ 來匹配 C 註釋會失敗,因為由於 .* 項目的貪婪性,它會匹配整個字串。

然而,如果量詞後跟一個問號,則它會變成惰性的,並匹配盡可能少的次數,因此模式 /\*.*?\*/ 可以正確處理 C 註釋。各種量詞的含義沒有其他改變,只是改變了首選的匹配次數。不要將問號的這種用法與其本身作為量詞的用法混淆。由於它有兩種用法,有時可能會出現雙重問號,例如 \d??\d,它優先匹配一個數字,但如果這是模式其餘部分匹配的唯一方法,則可以匹配兩個數字。

如果設定了 PCRE_UNGREEDY 選項(Perl 中不提供的選項),則量詞預設情況下不是貪婪的,但可以透過在它們後面加上問號使其變為貪婪的。換句話說,它反轉了預設行為。

後綴為 + 的量詞具有「佔有式」特性。它們會盡可能匹配最多字元,且不會回溯以匹配剩餘的模式。因此,.*abc 會匹配 "aabc",但 .*+abc 不會,因為 .*+ 會吃掉整個字串。佔有式量詞可用於提升處理速度。

當一個帶括號的子模式使用最小重複次數大於 1 或有限最大值的量詞時,編譯後的模式需要更多儲存空間,其大小與最小值或最大值成正比。

如果一個模式以 .* 或 .{0,} 開頭,且設定了 PCRE_DOTALL 選項(等同於 Perl 的 /s),允許 . 匹配換行符,則該模式會被隱式錨定,因為後續的模式會嘗試匹配目標字串中的每個字元位置,因此在第一個位置之後重試整體匹配沒有意義。PCRE 會將這樣的模式視為在其前面加上了 \A。如果已知目標字串不包含換行符,則當模式以 .* 開頭時,設定 PCRE_DOTALL 選項以獲得此優化,或者使用 ^ 明確指定錨定是值得的。

當一個帶有捕捉的子模式被重複時,捕捉到的值是匹配最後一次迭代的子字串。例如,在 (tweedle[dume]{3}\s*)+ 匹配 "tweedledum tweedledee" 之後,捕捉到的子字串的值是 "tweedledee"。但是,如果存在巢狀的帶有捕捉的子模式,則相應的捕捉值可能已在之前的迭代中設定。例如,在 /(a|(b))+/ 匹配 "aba" 之後,第二個捕捉到的子字串的值是 "b"。

新增註釋

使用者提供的註釋

此頁面沒有使用者提供的註釋。
To Top