快速入門
教學課程
工具和語言
範例
參考
書籍評論
正規運算式教學課程
簡介
目錄
特殊字元
不可列印字元
正規運算式引擎內部
字元類別
字元類別減法
字元類別交集
簡寫字元類別
錨點
字詞邊界
交替
選用項目
重複
群組和擷取
反向參照
反向參照,第 2 部分
命名群組
相對反向參照
分支重設群組
自由間距和註解
Unicode
模式修改器
原子群組
佔有量詞
前瞻和後顧
環顧,第 2 部分
保持文字不屬於匹配
條件式
平衡群組
遞迴
子常式
無限遞迴
遞迴和量詞
遞迴和擷取
遞迴和反向參照
遞迴和回溯
POSIX 方括號運算式
零長度匹配
持續匹配
本網站的其他資訊
簡介
正規運算式快速入門
正規運算式教學課程
替換字串教學課程
應用程式和語言
正規運算式範例
正規運算式參考
替換字串參考
書籍評論
可列印 PDF
關於本網站
RSS Feed 和部落格
RegexBuddy—Better than a regular expression tutorial!

保持目前匹配的文字不屬於整體正規運算式匹配

回溯通常用於比對特定文字,而該文字前有其他文字,但不會將其他文字包含在整體正規表示式比對中。 (?<=h)d 只比對 adhd 中的第二個 d。雖然許多正規表示式風味支援回溯,但大多數正規表示式風味只允許在回溯中使用正規表示式語法的子集。 PerlBoost 要求回溯長度固定。 PCRERuby 允許不同長度的 交替,但仍然不允許 量詞,除了長度固定的 {n}

為了克服回溯的限制,Perl 5.10、PCRE 7.2、Ruby 2.0 和 Boost 1.42 導入了一項新功能,可用於取代回溯最常見的目的。 \K 保留迄今比對的文字,不包含在整體正規表示式比對中。 h\Kd 只比對 adhd 中的第二個 d

JGsoft 風味 一直支援不受限制的 回溯,比 \K 靈活得多。不過,如果你偏好這種工作方式,JGsoft V2 也新增了對 \K 的支援。

深入了解正規表示式引擎

讓我們看看 h\Kd 如何運作。引擎從字串開頭開始比對嘗試。 h 無法比對 a。沒有其他交替可以嘗試。從字串開頭的比對嘗試失敗。

引擎在字串中前進一個字元,並再次嘗試比對。 h 無法比對 d

再次前進,h 比對 h。引擎在正規表示式中前進。正規表示式現在已到達正規表示式中的 \K,以及字串中 h 和第二個 d 之間的位置。 \K 除了告訴引擎,如果這個比對嘗試最終成功,正規表示式引擎應假裝比對嘗試從 hd 之間的目前位置開始,而不是從它實際開始的第一個 dh 之間開始。

引擎會透過正規表示式前進。d 會比對字串中的第二個 d。會找到一個整體比對。由於 \K 儲存的位置,字串中的第二個 d 會作為整體比對回傳。

\K 僅會影響成功比對後回傳的位置。它不會在比對過程中移動比對嘗試的開頭。hhh\Kd 正規表示式會比對 hhhhd 中的 d。此正規表示式會先在字串開頭比對 hhh。然後 \K 會記下字串中 hhhhd 之間的位置。然後 d 無法比對字串中的第四個 h。字串開頭的比對嘗試已失敗。

現在,引擎必須在字串中前進一個字元,才能開始下一個比對嘗試。它會從比對嘗試的實際開頭前進,也就是字串開頭。由 \K 儲存的位置不會變更這個位置。因此,第二次比對嘗試會從字串中第一個 h 後面的位置開始。從那裡開始,hhh 會比對 hhh\K 會記下位置,而 d 會比對 d。現在,會考量 \K 記住的位置,而 d 會作為整體比對回傳。

\K 可用於任何地方

你幾乎可以在任何正規表示式中的任何地方使用 \K。你應該避免在後向參照中使用它。你可以在群組中使用它,即使群組有量詞。你的正規表示式中可以有任意多個 \K 執行個體。(ab\Kc|d\Ke)f 會在 ab 之後比對 cf。在 d 之後,它也會比對 ef

\K 對於擷取群組沒有影響。當 (ab\Kc|d\Ke)f 符合 cf 時,擷取群組會擷取 abc,就好像 \K 不存在一樣。當正規表示式符合 ef 時,擷取群組會儲存 de

\K 的限制

由於 \K 對於正規表示式引擎執行比對程序的方式沒有影響,因此它比 Perl、PCRE 和 Ruby 中的後向參照提供更多彈性。您可以在 \K 的左方放置任何內容,但對於後向參照內部可以放置的內容有限制。

但是,這種彈性是有代價的。後向參照會真正往後比對字串。這允許後向參照在比對嘗試開始前檢查比對。當比對嘗試在先前比對的結尾開始時,後向參照可以比對先前比對中的一部分文字。\K 無法執行此動作,原因正是它對於正規表示式引擎執行比對程序的方式沒有影響。

如果您在字串 aaaa 中反覆執行 (?<=a)a 的所有比對,您將會得到三個比對:字串中的第二、第三和第四個 a。第一次比對嘗試從字串的開頭開始,並因為後向參照失敗而失敗。第二次比對嘗試從第一個和第二個 a 之間開始,後向參照成功,並比對到第二個 a。第三次比對嘗試從剛才比對到的第二個 a 之後開始。後向參照在此也成功。先前 a 是先前比對的一部分並無所謂。因此,第三次比對嘗試比對到第三個 a。同樣地,第四次比對嘗試比對到第四個 a。第五次比對嘗試從字串的結尾開始。後向參照仍然成功,但沒有任何字元可供 a 比對。比對嘗試失敗。引擎已到達字串的結尾,反覆執行停止。五次比對嘗試找到三個比對。

當您在字串 aaaa 中反覆運算 a\Ka 時,情況有所不同。您只會得到兩個配對:第二個和第四個 a。第一次配對嘗試從字串的開頭開始。正規表示式中的第一個 a 與字串中的第一個 a 相符。\K 標記位置。第二個 a 與字串中的第二個 a 相符,並回傳為第一個配對。第二次配對嘗試從剛剛配對的第二個 a 之後開始。正規表示式中的第一個 a 與字串中的第三個 a 相符。\K 標記位置。第二個 a 與字串中的第四個 a 相符,並回傳為第一個配對。第三次配對嘗試從字串的結尾開始。a 失敗。引擎已到達字串的結尾,且反覆運算停止。三次配對嘗試已找到兩個配對。

基本上,當正規表示式在 \K 之前的部分可以與正規表示式在 \K 之後的部分配對相同文字時,您就會遇到這個問題。如果這些部分無法與相同的文字配對,那麼使用 \K 的正規表示式將找到與使用後向參照重寫的相同正規表示式相同的配對。在這種情況下,您應該使用 \K 而不是後向參照,因為這樣可以在 Perl、PCRE 和 Ruby 中提供更好的效能。

另一個限制是,儘管後向參照有正向和負向變體,\K 並未提供否定的方式。 (?<!a)b 完全比對字串 b,因為它是一個未出現在「a」之前的「b」。 [^a]\Kb 完全不比對字串 b。在嘗試比對時,[^a] 比對 b。正規表示式現已到達字串的結尾。 \K 標示此位置。但現在 b 沒有任何東西可以比對了。比對嘗試失敗。 [^a]\Kb(?<=[^a])b 相同,而這兩個都與 (?<!a)b 不同。