PHP Conference Japan 2024

斷言

斷言是對目前匹配點之後或之前的字元進行的測試,但實際上不會消耗任何字元。以 \b、\B、\A、\Z、\z、^ 和 $ 編碼的簡單斷言在跳脫序列中說明。更複雜的斷言以子模式編碼。有兩種:一種是向前看主題字串中目前位置的,另一種是向後看的。

斷言子模式會以正常方式比對,但不會導致目前的比對位置變更。正向預查斷言以 (?= 開始表示肯定斷言,以 (?! 開始表示否定斷言。例如,\w+(?=;) 比對一個後面跟著分號的字詞,但不將分號包含在比對結果中,而 foo(?!bar) 比對任何未跟著 "bar" 的 "foo" 出現。請注意,看似相似的模式 (?!foo)bar 並不會找到前面不是 "foo" 的 "bar" 出現,它會找到任何 "bar" 的出現,因為當接下來的三個字元為 "bar" 時,斷言 (?!foo) 始終為 true。若要達成此效果,需要一個後向預查斷言。

反向預查斷言以 (?<= 開始表示肯定斷言,以 (?<! 開始表示否定斷言。例如,(?<!foo)bar 會找到前面不是 "foo" 的 "bar" 出現。反向預查斷言的內容受到限制,使其比對的所有字串都必須具有固定長度。但是,如果有數個替代方案,它們並不需要都具有相同的固定長度。因此,允許使用 (?<=bullock|donkey),但 (?<!dogs?|cats?) 會在編譯時產生錯誤。比對不同長度字串的分支僅允許在反向預查斷言的最上層使用。這是相較於 Perl 5.005 的擴充,後者要求所有分支都比對相同長度的字串。諸如 (?<=ab(c|de)) 之類的斷言不允許,因為其單一最上層分支可以比對兩種不同的長度,但如果改寫為使用兩個最上層分支則可接受:(?<=abc|abde) 反向預查斷言的實作方式是,對於每個替代方案,將目前位置暫時往回移動固定寬度,然後嘗試比對。如果目前位置之前沒有足夠的字元,則會認定比對失敗。反向預查結合僅執行一次的子模式,對於在字串末尾進行比對特別有用;在關於僅執行一次子模式的章節末尾會提供一個範例。

可以連續出現數個(任何種類的)斷言。例如,(?<=\d{3})(?<!999)foo 會比對前面有三個非 "999" 數字的 "foo"。請注意,每個斷言都會在主題字串中的同一個點獨立應用。首先檢查前三個字元是否都是數字,然後檢查相同的這三個字元是否不是 "999"。此模式不會比對前面有六個字元的 "foo",前三個字元是數字,而後三個字元不是 "999"。例如,它不會比對 "123abcfoo"。用來做到這一點的模式是 (?<=\d{3}...)(?<!999)foo

這次,第一個斷言會查看前六個字元,檢查前三個是否為數字,然後第二個斷言檢查前三個字元是否不是 "999"。

斷言可以以任何組合巢狀化。例如,(?<=(?<!foo)bar)baz 會比對前面是 "bar" 的 "baz" 出現,而 "bar" 前面又不是 "foo",而 (?<=\d{3}...(?!999))foo 是另一個比對 "foo" 的模式,其前面是三個數字和任何三個不是 "999" 的字元。

斷言子模式不是捕獲子模式,而且不能重複,因為重複斷言相同的內容沒有意義。如果任何種類的斷言包含其中的捕獲子模式,則在計算整個模式中的捕獲子模式的編號時會將其納入考量。但是,子字串捕獲僅針對肯定斷言執行,因為對否定斷言執行沒有意義。

斷言會計入 200 個括號子模式的最大值。

新增註解

使用者貢獻的註解

此頁面沒有使用者貢獻的註解。
To Top