檢視原始碼 re (stdlib v6.2)
此模組包含用於字串和二進位的正規表示式比對函式。
正規表示式的語法和語意類似 Perl。
該函式庫的比對演算法基於 PCRE 函式庫,但並非所有 PCRE 函式庫的功能都已介接,且該函式庫的某些部分的功能已超越 PCRE 的功能。目前使用 PCRE 版本 8.40 (發布日期為 2017-01-11)。與此模組相關的 PCRE 文件章節包含於此。
注意
Erlang 字串的字面語法使用
\\
(反斜線) 字元作為跳脫碼。您需要在字面字串中跳脫反斜線,無論是在您的程式碼中或是在 shell 中,都要使用額外的反斜線,也就是"\\\\"
或<<"\\\\">>
。自 Erlang/OTP 27 起,您可以使用逐字標記來寫入字面字串。上述範例會寫成
~S"\"
或~B"\"
。
類 Perl 正規表示式語法
下列各節包含此模組使用的正規表示式參考資料。此資訊基於 PCRE 文件,其中變更了此模組與 PCRE 函式庫的行為差異之處。
PCRE 正規表示式詳細資訊
下列各節詳細說明 PCRE 支援的正規表示式語法和語意。Perl 的正規表示式在其自身文件中說明,而一般的正規表示式則在許多書籍中介紹,其中一些書籍包含大量的範例。Jeffrey Friedl 出版的「精通正規表示式」(Mastering Regular Expressions) (O'Reilly 出版) 詳細介紹了正規表示式。此 PCRE 正規表示式的說明旨在作為參考資料。
參考資料分為以下幾節
- 特殊模式開頭項目
- 字元和中繼字元
- 反斜線
- 脫字符號和錢字符號
- 句點(點號)和 \N
- 比對單一資料單位
- 方括號和字元類別
- Posix 字元類別
- 垂直線
- 內部選項設定
- 子模式
- 重複子模式編號
- 具名子模式
- 重複
- 原子分組和佔有量詞
- 反向參考
- 斷言
- 條件子模式
- 註解
- 遞迴模式
- 子模式作為子常式
- Oniguruma 子常式語法
- 回溯控制
特殊模式開頭項目
某些可以傳遞給 compile/2
的選項也可以透過模式開頭的特殊項目進行設定。這些項目與 Perl 不相容,但提供這些項目是為了讓無法變更處理模式的程式之模式撰寫者也能存取這些選項。這些項目可以顯示任意次數,但它們必須全部一起出現在模式字串的開頭,而且字母必須為大寫。
UTF 支援
Unicode 支援基本上以 UTF-8 為基礎。若要使用 Unicode 字元,您可以呼叫具有 unicode
選項的 compile/2
或 run/3
,或模式必須以這些特殊序列之一開頭
(*UTF8)
(*UTF)
這兩個選項會產生相同的效果,輸入字串會解譯為 UTF-8。請注意,透過這些指示,re
函式不會執行清單到 UTF-8 的自動轉換。因此,不建議使用這些序列。改為在執行 compile/2
時新增 unicode
選項。
某些允許其使用者提供模式的應用程式可能希望基於安全性考量而將模式限制為非 UTF 資料。如果在編譯時設定 never_utf
選項,則不允許 (*UTF) 等項目,且其顯示會導致錯誤。
Unicode 屬性支援
以下是可以顯示在模式開頭的另一個特殊序列
(*UCP)
這與設定 ucp
選項的效果相同:它會導致 \d
和 \w
等序列使用 Unicode 屬性來判斷字元類型,而不是透過查閱表只辨識代碼 < 256 的字元。
停用啟動最佳化
如果模式以 (*NO_START_OPT)
開頭,則其效果與在編譯時設定 no_start_optimize
選項的效果相同。
換行慣例
PCRE 支援五種表示字串中換行符號的慣例:單一 CR (歸位字元) 字元、單一 LF (換行字元) 字元、雙字元序列 CRLF、上述三個的任一項,以及任何 Unicode 換行序列。
也可以透過以以下五個序列之一開頭模式字串來指定換行慣例
(*CR) - 歸位字元
(*LF) - 換行字元
(*CRLF) - >歸位字元後接著換行字元
(*ANYCRLF) - 上述三個的任一項
(*ANY) - 所有 Unicode 換行序列
這些會覆寫預設值和為 compile/2
指定的選項。例如,下列模式會將慣例變更為 CR
(*CR)a.b
此模式會比對 a\nb
,因為 LF 不再是換行符號。如果存在一個以上的換行慣例,則會使用最後一個慣例。
換行慣例會影響脫字符號和錢字符號斷言成立的位置。當未設定 dotall
時,也會影響點號中繼字元的解譯,以及 \N
的行為。不過,它不會影響 \R
跳脫序列比對的內容。根據預設,此為任何 Unicode 換行序列,以符合 Perl 的相容性。不過,此設定可以變更;請參閱 換行序列一節中 \R
的說明。\R
設定的變更可以與換行慣例的變更結合。
設定比對和遞迴限制
run/3
的呼叫者可以設定內部 match() 函式呼叫次數的限制,以及遞迴呼叫的最大深度。提供這些功能是為了捕捉由具有龐大比對樹狀結構的模式 (典型的範例是具有巢狀無限制重複的模式) 所引發的失控比對,並避免因過多的遞迴而耗盡系統堆疊。當達到這些限制之一時,pcre_exec()
會傳回錯誤。也可以透過模式開頭的項目以以下格式設定限制
(*LIMIT_MATCH=d)
(*LIMIT_RECURSION=d)
此處的 d 為任意的十進位數字。不過,設定的值必須小於 run/3
呼叫者設定的值,才會產生任何效果。也就是說,模式撰寫者可以降低程式設計師設定的限制,但不能提高它。如果其中一個限制有多個設定,則會使用較低的值。
在 Erlang VM 中,這兩個限制的預設值為 10,000,000。請注意,遞迴限制不會影響 VM 的堆疊深度,因為 Erlang 的 PCRE 會以 match 函式永遠不會在 C 堆疊上進行遞迴的方式編譯。
請注意,LIMIT_MATCH
和 LIMIT_RECURSION
只能降低呼叫者設定的限制值,而不能提高它們。
字元和中繼字元
正規表示式是一種模式,會從左至右比對主體字串。模式中的大多數字元代表自己,並比對主體中對應的字元。作為一個簡單的範例,下列模式會比對與自身相同的主體字串部分
The quick brown fox
當指定不區分大小寫比對 (選項 caseless
) 時,會比對字母而無論大小寫。
正規表示式的強大之處在於能夠在模式中包含替代方案和重複。這些是透過使用中繼字元編碼在模式中,中繼字元不代表自己,而是以某種特殊方式解譯。
存在兩組中繼字元:一組是在模式中的任何位置 (方括號內除外) 辨識的中繼字元,另一組是在方括號內辨識的中繼字元。在方括號外,中繼字元如下
\
- 具有多種用途的一般跳脫字元^
- 宣告字串開頭 (或多行模式下的行首)$
- 宣告字串結尾 (或多行模式下的行尾).
- 比對任何字元,換行符號除外 (預設)[
- 開始字元類別定義|
- 開始替代分支(
- 開始子模式)
- 結束子模式?
- 擴充 ( 的意義、也表示 0 或 1 量詞,也表示量詞最小化器*
- 0 個或多個量詞+
- 1 個或多個量詞,也表示「佔有量詞」{
- 開始最小/最大量詞
方括號內的部分模式稱為「字元類別」。以下是字元類別中唯一的中繼字元
\
- 一般跳脫字元^
- 否定類別,但前提是第一個字元-
- 表示字元範圍[
- Posix 字元類別 (僅當後面接著 Posix 語法時)]
- 終止字元類別
下列各節說明每個中繼字元的使用方式。
反斜線
反斜線字元有多種用途。首先,如果它後面接著的字元不是數字或字母,則它會移除字元可能擁有的任何特殊含義。反斜線作為跳脫字元的使用方式適用於字元類別的內部和外部。
例如,如果您想要匹配 "_" 字元,您可以在模式中寫入 \_
。此跳脫動作適用於當後續的字元會被解讀為元字元的情況,因此,為了明確指定非字母數字字元代表其本身,在其前面加上反斜線總是安全的。特別是,如果您想要匹配反斜線,請寫入 \\
。
在 unicode
模式下,只有 ASCII 數字和字母在反斜線後才具有特殊含義。所有其他字元(特別是代碼點 > 127 的字元)都被視為字面值。
如果模式使用 extended
選項編譯,則模式中的空白字元(字元類別內除外)以及在字元類別外的 # 字元和下一個換行符號之間的字元都會被忽略。可以使用跳脫反斜線來將空白字元或 # 字元包含在模式中。
若要移除一串字元的特殊含義,請將它們放在 \Q
和 \E
之間。這與 Perl 的不同之處在於,$
和 @
在 PCRE 的 \Q
...\E
序列中被視為字面值,而 $
和 @
會在 Perl 中導致變數內插。請注意以下範例
Pattern PCRE matches Perl matches
\Qabc$xyz\E abc$xyz abc followed by the contents of $xyz
\Qabc\$xyz\E abc\$xyz abc\$xyz
\Qabc\E\$\Qxyz\E abc$xyz abc$xyz
\Q
...\E
序列在字元類別內部和外部都可識別。未由 \Q
開頭的孤立 \E
會被忽略。如果 \Q
後面在模式中沒有 \E
,則字面值解釋會持續到模式結束(也就是說,會假定模式末尾有 \E
)。如果孤立的 \Q
在字元類別內部,則會導致錯誤,因為字元類別未終止。
非列印字元
反斜線的第二種用途是以可見的方式在模式中編碼非列印字元。除了終止模式的二進位零之外,非列印字元的外觀沒有任何限制。當透過文字編輯準備模式時,通常更容易使用以下跳脫序列之一,而不是它所代表的二進位字元
\a
- 響鈴,即 BEL 字元(十六進位 07)\cx
-「Control-x」,其中 x 是任何 ASCII 字元\e
- 跳脫(十六進位 1B)\f
- 換頁(十六進位 0C)\n
- 換行(十六進位 0A)\r
- 歸位(十六進位 0D)\t
- Tab(十六進位 09)\0dd
- 八進位碼為 0dd 的字元\ddd
- 八進位碼為 ddd 的字元,或反向參照\o{ddd..}
- 八進位碼為 ddd.. 的字元\xhh
- 十六進位碼為 hh 的字元\x{hhh..}
- 十六進位碼為 hhh.. 的字元
注意
請注意,
\0dd
永遠是八進位碼,而\8
和\9
是字面字元「8」和「9」。
\cx
對 ASCII 字元的確切作用如下:如果 x 是小寫字母,則會將其轉換為大寫字母。然後,反轉字元的第 6 位元(十六進位 40)。因此,\cA
到 \cZ
變成十六進位 01 到十六進位 1A(A 是 41,Z 是 5A),但 \c{
變成十六進位 3B({
是 7B),而 \c
; 變成十六進位 7B(; 是 3B)。如果 \c
後面的資料項目(位元組或 16 位元值)的值 > 127,則會發生編譯時錯誤。這會在所有模式中鎖定非 ASCII 字元。
\c
功能最初設計用於 ASCII 字元,但隨著擴展到 Unicode,它甚至比以前更沒用。
在 \0
之後,最多會讀取另外兩個八進位數字。如果少於兩個數字,則只會使用現有的數字。因此,序列 \0\x\015
指定兩個二進位零,後跟一個 CR 字元(代碼值 13)。如果後續的模式字元本身是八進位數字,請確保在初始零之後提供兩個數字。
跳脫字元 \o
後面必須接著以大括號括住的八進位數字序列。如果不是這樣,則會發生錯誤。此跳脫是 Perl 最近新增的功能;它提供了一種將字元碼點指定為大於 0777 的八進位數字的方法,並且還允許明確指定八進位數字和反向參照。
為了更清晰明確,最好避免在 \
後面接著大於零的數字。相反,請使用 \o{}
或 \x{}
來指定字元數字,並使用 \g{}
來指定反向參照。以下段落描述了舊的、不明確的語法。
反斜線後接非 0 數字的處理方式很複雜,而且 Perl 在最近的版本中已變更,也導致 PCRE 發生變更。在字元類別外部,PCRE 會將數字和任何後續數字讀取為十進位數字。如果該數字 < 8,或如果表達式中至少已存在那麼多個先前的捕捉左括號,則會將整個序列視為反向參照。稍後在討論括號子模式之後,會提供有關其運作方式的說明。
在字元類別內部,或如果 \
後面的十進位數字 > 7 且沒有那麼多個捕捉子模式,則 PCRE 會將 \8
和 \9
處理為字面字元「8」和「9」,否則會重新讀取反斜線後面的最多三個八進位數字,並使用它們來產生資料字元。任何後續數字都代表它們自身。例如
\040
- 寫入 ASCII 空格的另一種方式\40
- 相同,前提是先前有 < 40 個捕捉子模式\7
- 永遠是反向參照\11
- 可以是反向參照,或是寫入 Tab 的另一種方式\011
- 永遠是 Tab\0113
- 一個 Tab,後接字元「3」\113
- 可以是反向參照,否則為八進位碼 113 的字元\377
- 可以是反向參照,否則為值 255(十進位)\81
- 可能是反向參照,或是兩個字元「8」和「1」
請注意,使用此語法指定的八進位值 >= 100 不能以首碼零引入,因為最多只會讀取三個八進位數字。
預設情況下,在 \x
後面沒有 {
的情況下,會讀取零到兩個十六進位數字(字母可以是大寫或小寫)。在 \x{
和 }
之間可能會出現任意數量的十六進位數字。如果 \x{
和 }
之間出現非十六進位數字的字元,或者如果沒有終止的 }
,則會發生錯誤。
值小於 256 的字元可以使用 \x
的兩種語法中的任一種來定義。它們的處理方式沒有差異。例如,\xdc
與 \x{dc}
完全相同。
字元值的限制
使用八進位或十六進位數字指定的字元僅限於某些值,如下所示
8 位元非 UTF 模式 - < 0x100
8 位元 UTF-8 模式 - < 0x10ffff 和有效碼點
無效的 Unicode 碼點是 0xd800 到 0xdfff 範圍(所謂的「代理」碼點)和 0xffef。
字元類別中的跳脫序列
定義單一字元值的所有序列都可以在字元類別內部和外部使用。此外,在字元類別內部,\b
會被解讀為退格字元(十六進位 08)。
字元類別中不允許使用 \N
。\B
、\R
和 \X
在字元類別內部不是特殊的。與其他無法辨識的跳脫序列一樣,它們會被視為字面字元「B」、「R」和「X」。在字元類別外部,這些序列具有不同的含義。
不支援的跳脫序列
在 Perl 中,序列 \l
、\L
、\u
和 \U
由其字串處理常式辨識,並用於修改後續字元的大小寫。PCRE 不支援這些跳脫序列。
絕對和相對反向參照
序列 \g
後面接著一個不帶正負號的或負數的數字(選擇性地以大括號括住),是絕對或相對反向參照。具名反向參照可以編碼為 \g{name}
。稍後在討論括號子模式之後,會討論反向參照。
絕對和相對子程式呼叫
為了與 Oniguruma 相容,非 Perl 語法 \g
後面接著以角括號或單引號括住的名稱或數字,是將子模式參照為「子程式」的替代語法。稍後會討論詳細資訊。請注意,\g{...}
(Perl 語法)和 \g<...>
(Oniguruma 語法)並非同義詞。前者是反向參照,後者是子程式呼叫。
一般字元類型
反斜線的另一種用途是指定一般字元類型
\d
- 任何十進位數字\D
- 任何非十進位數字的字元\h
- 任何水平空白字元\H
- 任何非水平空白字元的字元\s
- 任何空白字元\S
- 任何非空白字元的字元\v
- 任何垂直空白字元\V
- 任何非垂直空白字元的字元\w
- 任何「單字」字元\W
- 任何「非單字」字元
還有單一序列 \N
,它會比對非換行字元。當未設定 dotall
時,這與「.」元字元相同。Perl 也使用 \N
來依名稱比對字元,但 PCRE 不支援此功能。
每對小寫和大寫跳脫序列將完整的字元集劃分為兩個不相交的集合。任何給定的字元都與每對中的一個且只有一個相符。這些序列可以出現在字元類別內部和外部。它們各自比對適當類型的一個字元。如果目前的比對點位於主體字串的末尾,則全部都會失敗,因為沒有要比對的字元。
為了與 Perl 相容,\s
過去不匹配 VT 字元(碼位 11),這使其與 POSIX 的「空白」類別不同。然而,Perl 在 5.18 版本加入了 VT,而 PCRE 在 8.34 版本也跟進了。現在預設的 \s
字元為 HT (9)、LF (10)、VT (11)、FF (12)、CR (13) 和空格 (32),這些在「C」語系中被定義為空白字元。如果正在進行與語系相關的匹配,則此列表可能會有所不同。例如,在某些語系中,「不換行空格」字元(\xA0
)被視為空白字元,而在其他語系中,VT 字元則不是。
「單字」字元是一個底線或任何字母或數字的字元。預設情況下,字母和數字的定義由 PCRE 低值字元表控制,在 Erlang 的情況下(且沒有 unicode
選項),則為 ISO Latin-1 字元集。
預設情況下,在 unicode
模式中,值大於 255 的字元,也就是所有 ISO Latin-1 字元集之外的字元,永遠不會匹配 \d
、\s
或 \w
,並且永遠會匹配 \D
、\S
和 \W
。這些序列保留了在 UTF 支援可用之前它們的原始含義,主要是為了效率考量。但是,如果設定了 ucp
選項,則會變更行為,以便使用 Unicode 屬性來判斷字元類型,如下所示:
\d
- 任何符合\p{Nd}
的字元(十進位數字)\s
- 任何符合\p{Z}
或\h
或\v
的字元\w
- 任何符合\p{L}
或\p{N}
的字元,加上底線
大寫的跳脫字元會匹配反向的字元集合。請注意,\d
僅匹配十進位數字,而 \w
則匹配任何 Unicode 數字、任何 Unicode 字母和底線。另請注意,ucp
會影響 \b
和 \B
,因為它們是根據 \w
和 \W
定義的。當設定 ucp
時,匹配這些序列的速度明顯較慢。
序列 \h
、\H
、\v
和 \V
是在 Perl 5.10 版本中新增的功能。與預設情況下僅匹配 ASCII 字元的其他序列不同,這些序列始終會匹配某些高碼位,無論是否設定了 ucp
。
以下是水平空格字元:
U+0009 - 水平製表符 (HT)
U+0020 - 空格
U+00A0 - 不換行空格
U+1680 - 歐甘空格標記
U+180E - 蒙古語母音分隔符號
U+2000 - 半角全形空格
U+2001 - 全角全形空格
U+2002 - 半角空格
U+2003 - 全角空格
U+2004 - 三分之一全形空格
U+2005 - 四分之一全形空格
U+2006 - 六分之一全形空格
U+2007 - 數字空格
U+2008 - 標點空格
U+2009 - 極細空格
U+200A - 髮絲空格
U+202F - 窄不換行空格
U+205F - 中等數學空格
U+3000 - 表意文字空格
以下是垂直空格字元:
U+000A - 換行符號 (LF)
U+000B - 垂直製表符 (VT)
U+000C - 換頁符號 (FF)
U+000D - 回車符號 (CR)
U+0085 - 下一行 (NEL)
U+2028 - 行分隔符號
U+2029 - 段落分隔符號
在 8 位元非 UTF-8 模式中,只有碼位 < 256 的字元才相關。
換行序列
在字元類別之外,預設情況下,跳脫序列 \R
會匹配任何 Unicode 換行序列。在非 UTF-8 模式中,\R
等同於以下:
(?>\r\n|\n|\x0b|\f|\r|\x85)
這是一個「原子群組」的範例,詳細資訊如下所述。
這個特定的群組匹配雙字元序列 CR 後接 LF,或單個字元 LF(換行符號,U+000A)、VT(垂直製表符,U+000B)、FF(換頁符號,U+000C)、CR(回車符號,U+000D)或 NEL(下一行,U+0085)之一。雙字元序列被視為不可分割的單一單位。
在 Unicode 模式中,會新增兩個碼位 > 255 的字元:LS(行分隔符號,U+2028)和 PS(段落分隔符號,U+2029)。不需要 Unicode 字元屬性支援即可識別這些字元。
可以透過在編譯時或匹配模式時設定 bsr_anycrlf
選項,將 \R
限制為僅匹配 CR、LF 或 CRLF(而不是完整的 Unicode 行尾集)。(BSR 是「反斜線 R」的縮寫。)這可以在建置 PCRE 時設為預設值;如果是這樣,則可以透過 bsr_unicode
選項請求其他行為。這些設定也可以透過在模式字串開頭加入以下序列之一來指定:
(*BSR_ANYCRLF) - 僅 CR、LF 或 CRLF
(*BSR_UNICODE) - 任何 Unicode 換行序列
這些會覆蓋預設值和編譯函數指定的選項,但它們本身可以被匹配函數指定的選項覆蓋。請注意,這些特殊的設定(與 Perl 不相容)僅在模式的最開始處被識別,並且它們必須為大寫。如果存在多個設定,則使用最後一個設定。它們可以與換行慣例的變更結合使用;例如,模式可以從以下開始:
(*ANY)(*BSR_ANYCRLF)
它們也可以與 (UTF8)、(UTF) 或 (*UCP) 特殊序列結合使用。在字元類別中,\R
被視為無法識別的跳脫序列,因此預設情況下匹配字母「R」。
Unicode 字元屬性
還有三個跳脫序列可用於匹配具有特定屬性的字元。當處於 8 位元非 UTF-8 模式時,這些序列僅限於測試碼位 < 256 的字元,但它們在此模式下仍然有效。以下是額外的跳脫序列:
\p{_xx_}
- 具有屬性 _xx_ 的字元\P{_xx_}
- 不具有屬性 _xx_ 的字元\X
- Unicode 擴展字形群集
上面由 _xx_ 表示的屬性名稱僅限於 Unicode 腳本名稱、一般類別屬性、「Any」(匹配任何字元,包括換行符號)以及一些特殊的 PCRE 屬性(在下一節中說明)。其他 Perl 屬性(例如「InMusicalSymbols」)目前不被 PCRE 支援。請注意,\P{Any}
不匹配任何字元,且始終會導致匹配失敗。
Unicode 字元集被定義為屬於特定的腳本。可以使用腳本名稱來匹配來自這些集合之一的字元,例如:
\p{Greek} \P{Han}
那些不屬於已識別腳本的字元被歸類為「Common」。以下是目前的腳本列表:
- Arabic(阿拉伯文)
- Armenian(亞美尼亞文)
- Avestan(阿維斯陀文)
- Balinese(峇里文)
- Bamum(巴姆文)
- Bassa_Vah(巴薩瓦文)
- Batak(巴塔克文)
- Bengali(孟加拉文)
- Bopomofo(注音符號)
- Braille(點字)
- Buginese(布吉文)
- Buhid(布希德文)
- Canadian_Aboriginal(加拿大原住民文)
- Carian(卡里亞文)
- Caucasian_Albanian(高加索阿爾巴尼亞文)
- Chakma(查克瑪文)
- Cham(占文)
- Cherokee(切羅基文)
- Common(通用)
- Coptic(科普特文)
- Cuneiform(楔形文字)
- Cypriot(塞浦路斯文)
- Cyrillic(西里爾文)
- Deseret(猶他文)
- Devanagari(天城文)
- Duployan(杜普洛伊文)
- Egyptian_Hieroglyphs(埃及象形文字)
- Elbasan(埃爾巴桑文)
- Ethiopic(衣索比亞文)
- Georgian(喬治亞文)
- Glagolitic(格拉哥里文)
- Gothic(哥德文)
- Grantha(格蘭塔文)
- Greek(希臘文)
- Gujarati(古吉拉特文)
- Gurmukhi(古木基文)
- Han(漢字)
- Hangul(韓文)
- Hanunoo(哈努諾文)
- Hebrew(希伯來文)
- Hiragana(平假名)
- Imperial_Aramaic(帝國亞蘭文)
- Inherited(繼承)
- Inscriptional_Pahlavi(銘文巴列維文)
- Inscriptional_Parthian(銘文帕提亞文)
- Javanese(爪哇文)
- Kaithi(凱提文)
- Kannada(卡納達文)
- Katakana(片假名)
- Kayah_Li(克耶里文)
- Kharoshthi(佉盧文)
- Khmer(高棉文)
- Khojki(霍吉基文)
- Khudawadi(庫達瓦迪文)
- Lao(寮文)
- Latin(拉丁文)
- Lepcha(雷布查文)
- Limbu(林布文)
- Linear_A(線形文字 A)
- Linear_B(線形文字 B)
- Lisu(傈僳文)
- Lycian(呂基亞文)
- Lydian(呂底亞文)
- Mahajani(馬哈賈尼文)
- Malayalam(馬拉雅拉姆文)
- Mandaic(曼達文)
- Manichaean(摩尼文)
- Meetei_Mayek(梅泰馬耶克文)
- Mende_Kikakui(門德基卡庫伊文)
- Meroitic_Cursive(麥羅埃草書體)
- Meroitic_Hieroglyphs(麥羅埃象形文字)
- Miao(苗文)
- Modi(莫迪文)
- Mongolian(蒙古文)
- Mro(姆羅文)
- Myanmar(緬甸文)
- Nabataean(納巴泰文)
- New_Tai_Lue(新傣仂文)
- Nko(恩科文)
- Ogham(歐甘文)
- Ol_Chiki(奧爾奇基文)
- Old_Italic(古義大利文)
- Old_North_Arabian(古北阿拉伯文)
- Old_Permic(古彼爾姆文)
- Old_Persian(古波斯文)
- Oriya(奧里亞文)
- Old_South_Arabian(古南阿拉伯文)
- Old_Turkic(古突厥文)
- Osmanya(奧斯曼亞文)
- Pahawh_Hmong(巴哈蒙文)
- Palmyrene(巴爾米拉文)
- Pau_Cin_Hau(包秦豪文)
- Phags_Pa(八思巴文)
- Phoenician(腓尼基文)
- Psalter_Pahlavi(聖詩巴列維文)
- Rejang(雷讓文)
- Runic(盧恩文)
- Samaritan(撒馬利亞文)
- Saurashtra(索拉什特拉文)
- Sharada(夏拉達文)
- Shavian(蕭伯納文)
- Siddham(悉曇文)
- Sinhala(僧伽羅文)
- Sora_Sompeng(索拉松彭文)
- Sundanese(巽他文)
- Syloti_Nagri(錫爾赫特文)
- Syriac(敘利亞文)
- Tagalog(他加祿文)
- Tagbanwa(塔格巴努亞文)
- Tai_Le(傣仂文)
- Tai_Tham(蘭納文)
- Tai_Viet(傣越文)
- Takri(塔克里文)
- Tamil(泰米爾文)
- Telugu(泰盧固文)
- Thaana(塔納文)
- Thai(泰文)
- Tibetan(藏文)
- Tifinagh(提非納文)
- Tirhuta(蒂爾胡塔文)
- Ugaritic(烏加里特文)
- Vai(瓦伊文)
- Warang_Citi(瓦朗齊蒂文)
- Yi(彝文)
每個字元都有一個 Unicode 一般類別屬性,由兩個字母的縮寫指定。為了與 Perl 相容,可以使用插入符號來指定否定,插入符號位於左大括號和屬性名稱之間。例如,\p{^Lu}
與 \P{Lu}
相同。
如果使用 \p
或 \P
只指定一個字母,則它會包含所有以該字母開頭的一般類別屬性。在這種情況下,在沒有否定的情況下,跳脫序列中的大括號是可選的。以下兩個範例具有相同的效果:
\p{L}
\pL
支援以下一般類別屬性代碼:
C - 其他
Cc - 控制
Cf - 格式
Cn - 未分配
Co - 私人使用
Cs - 代理
L - 字母
Ll - 小寫字母
Lm - 修飾字母
Lo - 其他字母
Lt - 詞首大寫字母
Lu - 大寫字母
M - 符號
Mc - 間隔符號
Me - 封閉符號
Mn - 非間隔符號
N - 數字
Nd - 十進位數字
Nl - 字母數字
No - 其他數字
P - 標點符號
Pc - 連接符標點符號
Pd - 破折號標點符號
Pe - 關閉標點符號
Pf - 結尾標點符號
Pi - 起始標點符號
Po - 其他標點符號
Ps - 開啟標點符號
S - 符號
Sc - 貨幣符號
Sk - 修飾符號
Sm - 數學符號
So - 其他符號
Z - 分隔符
Zl - 行分隔符
Zp - 段落分隔符
Zs - 空格分隔符
也支援特殊屬性 L&。它匹配具有 Lu、Ll 或 Lt 屬性的字元,也就是未分類為修飾字或「其他」的字母。
Cs (代理) 屬性僅適用於 U+D800 到 U+DFFF 範圍內的字元。此類字元在 Unicode 字串中無效,因此無法透過 PCRE 測試。Perl 不支援 Cs 屬性。
PCRE 不支援 Perl 支援的屬性名稱的長同義詞 (例如 \p{Letter}
)。 不允許在任何這些屬性前面加上 "Is" 前綴。
Unicode 表格中沒有任何字元具有 Cn (未分配) 屬性。此屬性假設用於 Unicode 表格中不存在的任何程式碼點。
指定不區分大小寫的匹配不會影響這些跳脫序列。例如,\p{Lu}
永遠只匹配大寫字母。這與目前版本的 Perl 的行為不同。
透過 Unicode 屬性匹配字元的速度不快,因為 PCRE 必須執行多階段表格查詢才能找到字元屬性。這就是為什麼傳統跳脫序列 (例如 \d
和 \w
) 預設情況下不使用 PCRE 中的 Unicode 屬性的原因。但是,您可以透過設定選項 ucp
或以 (*UCP)
開頭模式來使其執行此操作。
擴展字形叢集
\X
跳脫字元匹配形成「擴展字形叢集」的任意數量的 Unicode 字元,並將該序列視為一個原子群組 (請參閱下方)。在 8.31 版及更早的版本中,PCRE 匹配的是較早、較簡單的定義,相當於 (?>\PM\pM*)
。也就是說,它匹配一個沒有「符號」屬性的字元,然後是零或多個具有「符號」屬性的字元。具有「符號」屬性的字元通常是不佔空間的重音符號,會影響前面的字元。
Unicode 將此簡單定義擴展為包含更複雜的複合字元,方法是為每個字元提供字形斷裂屬性,並建立使用這些屬性來定義擴展字形叢集邊界的規則。在 8.31 版之後的 PCRE 版本中,\X
匹配這些叢集之一。
\X
永遠至少匹配一個字元。然後,它會根據以下規則決定是否加入更多字元來結束叢集
- 在主體字串的結尾結束。
- 不要在 CR 和 LF 之間結束;否則在任何控制字元之後結束。
- 不要中斷韓文 (一種韓國文字) 音節序列。韓文字元有五種類型:L、V、T、LV 和 LVT。L 字元後面可以接 L、V、LV 或 LVT 字元。LV 或 V 字元後面可以接 V 或 T 字元。LVT 或 T 字元只能接 T 字元。
- 不要在延伸字元或間隔符號之前結束。具有「符號」屬性的字元永遠具有「延伸」字形斷裂屬性。
- 不要在附加字元之後結束。
- 否則,結束叢集。
PCRE 其他屬性
除了前面說明的標準 Unicode 屬性之外,PCRE 還支援其他四個屬性,使其能夠轉換傳統的跳脫序列 (例如 \w
和 \s
) 以使用 Unicode 屬性。當傳遞 ucp
選項時,PCRE 會在內部使用這些非標準、非 Perl 屬性。但是,它們也可以明確使用。屬性如下
Xan - 任何字母數字字元。匹配具有 L (字母) 或 N (數字) 屬性的字元。
Xps - 任何 Posix 空格字元。匹配字元 Tab、換行、垂直 Tab、換頁、歸位和任何具有 Z (分隔符) 屬性的其他字元。
Xsp - 任何 Perl 空格字元。除了垂直 Tab 之外,與 Xps 匹配的字元相同。
Xwd - 任何 Perl「文字」字元。匹配與 Xan 相同的字元,加上底線。
Perl 和 POSIX 空格現在相同。Perl 在 5.18 版中將 VT 新增至其空格字元集,而 PCRE 在 8.34 版中變更。
Xan 匹配具有 L (字母) 或 N (數字) 屬性的字元。Xps 匹配字元 Tab、換行、垂直 Tab、換頁或歸位和任何具有 Z (分隔符) 屬性的其他字元。Xsp 與 Xps 相同;過去為了與 Perl 相容而排除垂直 Tab,但 Perl 進行了變更,因此 PCRE 在 8.34 版中跟進。Xwd 匹配與 Xan 相同的字元,加上底線。
還有另一個非標準屬性 Xuc,它匹配 C++ 和其他程式語言中可透過通用字元名稱表示的任何字元。這些字元是 $
、@
、`
(重音符號) 和所有 Unicode 程式碼點 >= U+00A0 的字元,但代理 U+D800 到 U+DFFF 除外。請注意,大多數基本 (ASCII) 字元都排除在外。(通用字元名稱的形式為 \uHHHH
或 \UHHHHHHHH
,其中 H 是十六進位數字。請注意,Xuc 屬性不匹配這些序列,而是匹配它們所代表的字元。)
重設匹配開始位置
\K
跳脫序列會使任何先前匹配的字元不包含在最終匹配的序列中。例如,以下模式匹配「foobar」,但報告它已匹配「bar」
foo\Kbar
此功能類似於後向斷言 (如下所述)。但是,在這種情況下,實際匹配之前的目標字串部分不必具有固定長度,就像後向斷言一樣。\K
的使用不會干擾捕獲子字串的設定。例如,當以下模式匹配「foobar」時,第一個子字串仍然設定為「foo」
(foo)\Kbar
Perl 文件指出在斷言中使用 \K
「沒有明確定義」。在 PCRE 中,\K
會在出現在肯定斷言內時執行,但在否定斷言中會被忽略。請注意,當模式 (例如 (?=ab\K)
) 匹配時,回報的匹配開始位置可能大於匹配的結束位置。
簡單斷言
反斜線的最終用途是用於某些簡單斷言。斷言指定在匹配中的特定點必須滿足的條件,而不會使用目標字串中的任何字元。使用子模式來進行更複雜的斷言會在下面說明。以下是反斜線斷言
\b
- 在文字邊界處匹配。\B
- 不在文字邊界處時匹配。\A
- 在主體的開頭匹配。\Z
- 在主體的結尾,以及在主體結尾處的換行符號之前匹配。\z
- 僅在主體的結尾匹配。\G
- 在主體中的第一個匹配位置匹配。
在字元類別內部,\b
具有不同的含義;它匹配退格字元。如果這些斷言中的任何其他斷言出現在字元類別中,則預設情況下它會匹配相應的常值字元 (例如,\B
會匹配字母 B)。
文字邊界是目標字串中的一個位置,其中目前的字元和先前的字元不會都匹配 \w
或 \W
(也就是說,一個匹配 \w
,另一個匹配 \W
),如果第一個或最後一個字元分別匹配 \w
,則為字串的開頭或結尾。在 UTF 模式中,可以透過設定選項 ucp
來變更 \w
和 \W
的含義。完成此操作後,也會影響 \b
和 \B
。PCRE 和 Perl 沒有單獨的「文字開頭」或「文字結尾」中繼序列。但是,\b
後面的任何內容通常會決定它是哪一個。例如,片段 \ba
在文字開頭匹配「a」。
\A
、\Z
和 \z
斷言與傳統的脫字符號和貨幣符號 (在下一節中說明) 不同,它們永遠只在目標字串的開頭和結尾處匹配,無論設定了哪些選項。因此,它們與多行模式無關。這三個斷言不受選項 notbol
或 noteol
的影響,這些選項只會影響脫字符號和貨幣符號中繼字元的行為。但是,如果 run/3
的引數 startoffset
非零,表示匹配從主體的開頭以外的點開始,\A
永遠無法匹配。 \Z
和 \z
的區別在於,\Z
在字串結尾的換行符號之前和最後匹配,而 \z
只在結尾匹配。
只有當目前的匹配位置位於匹配的起始點時,\G
斷言才為 true,這由 run/3
的引數 startoffset
指定。當 startoffset
的值非零時,它與 \A
不同。透過使用適當的引數多次呼叫 run/3
,您可以模擬 Perl 選項 /g
,而 \G
在這種實作中很有用。
但是,請注意,PCRE 將 \G
解釋為目前匹配的開始位置,這與 Perl 的定義略有不同,Perl 將其定義為先前匹配的結束位置。在 Perl 中,當先前匹配的字串為空時,它們可能不同。由於 PCRE 一次只執行一個匹配,因此無法重現此行為。
如果模式的所有替代方案都以 \G
開頭,則表示式會錨定到起始匹配位置,並且「錨定」旗標會設定在編譯的正規表示式中。
脫字符號和貨幣符號
脫字符號 (circumflex) 和錢字符號 (dollar) 是零寬度斷言。也就是說,它們測試特定條件是否為真,而不會從主體字串中消耗任何字元。
在字元類別之外,於預設比對模式中,脫字符號是一個斷言,只有在目前比對點位於主體字串的開頭時才會成立。如果 run/3
的參數 startoffset
非零,且選項 multiline
未設定,則脫字符號永遠無法比對成功。在字元類別內,脫字符號有完全不同的含義 (請參閱下文)。
如果包含某些替代方案,脫字符號不必是模式的第一個字元,但如果要使模式比對到該分支,則它必須是每個出現的替代方案中的第一個元素。如果所有可能的替代方案都以脫字符號開頭,也就是說,如果模式被限制為僅在主體字串的開頭進行比對,則稱之為「錨定」模式。(還有其他結構可以使模式被錨定。)
錢字符號是一個斷言,只有在目前比對點位於主體字串的結尾,或緊接在字串結尾的換行符之前時才會成立 (預設情況下)。但是請注意,它不會比對換行符。如果包含某些替代方案,錢字符號不必是模式的最後一個字元,但它必須是任何出現分支中的最後一個項目。錢字符號在字元類別中沒有特殊含義。
可以透過在編譯時設定選項 dollar_endonly
來更改錢字符號的含義,使其僅在字串的末尾進行比對。這不會影響 \Z
斷言。
如果設定了選項 multiline
,則脫字符號和錢字符號的含義會被更改。在這種情況下,脫字符號會比對緊接在內部換行符之後以及主體字串開頭的位置。它不會比對位於字串結尾的換行符之後的位置。當設定 multiline
時,錢字符號會比對字串中任何換行符之前的位置,以及字串的末尾。當換行符指定為雙字元序列 CRLF 時,單獨的 CR 和 LF 字元不表示換行符。
例如,模式 /^abc$/
在多行模式下會比對主體字串 "def\nabc" (其中 \n 代表換行符),否則不會。因此,由於所有分支都以 ^ 開頭而在單行模式下錨定的模式,在多行模式下不會被錨定,並且當 run/3
的參數 startoffset 非零時,可能會比對到脫字符號。如果設定了 multiline
,則會忽略選項 dollar_endonly
。
請注意,序列 \A
、\Z
和 \z
可用於在兩種模式下比對主體的開頭和結尾。如果模式的所有分支都以 \A
開頭,則無論是否設定了 multiline
,它都始終被錨定。
句點 (英文句號、點) 和 \N
在字元類別之外,模式中的點會比對主體字串中的任何字元,但 (預設情況下) 表示行尾的字元除外。
當行尾被定義為單個字元時,點永遠不會比對該字元。當使用雙字元序列 CRLF 時,如果 CR 後面緊跟著 LF,則點不會比對 CR,否則它會比對所有字元 (包括單獨的 CR 和 LF)。當識別任何 Unicode 行尾時,點不會比對 CR、LF 或任何其他行尾字元。
點關於換行符的行為可以被更改。如果設定了選項 dotall
,則點會比對任何字元,沒有例外。如果主體字串中存在雙字元序列 CRLF,則需要兩個點才能比對它。
點的處理完全獨立於脫字符號和錢字符號的處理,它們之間唯一的關係是兩者都涉及換行符。點在字元類別中沒有特殊含義。
逸出序列 \N
的行為類似於點,只是它不受選項 PCRE_DOTALL
的影響。也就是說,它會比對除表示行尾的字元以外的任何字元。Perl 也使用 \N
按名稱比對字元,但 PCRE 不支援此功能。
比對單個資料單元
在字元類別之外,逸出序列 \C
會比對任何資料單元,無論是否設定了 UTF 模式。一個資料單元是一個位元組。與點不同,\C
始終會比對行尾字元。Perl 中提供此功能是為了在 UTF-8 模式下比對個別位元組,但尚不清楚如何有效地使用它。由於 \C
會將字元分解為個別的資料單元,因此在 UTF 模式下使用 \C
比對一個單元表示剩餘的字串可能會以格式錯誤的 UTF 字元開頭。這會產生未定義的結果,因為 PCRE 假設它處理的是有效的 UTF 字串。
PCRE 不允許 \C
出現在 UTF 模式下的後向斷言中 (如下所述),因為這會導致無法計算後向斷言的長度。
最好避免使用 \C
逸出序列。但是,避免格式錯誤的 UTF 字元問題的一種方法是使用前向斷言來檢查下一個字元的長度,如下列模式所示,該模式可以與 UTF-8 字串一起使用 (忽略空白和換行符):
(?| (?=[\x00-\x7f])(\C) |
(?=[\x80-\x{7ff}])(\C)(\C) |
(?=[\x{800}-\x{ffff}])(\C)(\C)(\C) |
(?=[\x{10000}-\x{1fffff}])(\C)(\C)(\C)(\C))
以 (?| 開頭的群組會重置每個替代方案中的捕獲括號編號 (請參閱 重複子模式編號 一節)。每個分支開頭的斷言分別檢查下一個 UTF-8 字元的值,這些值使用的編碼分別使用 1、2、3 或 4 個位元組。然後,字元的個別位元組由適當的群組數量捕獲。
方括號和字元類別
開方括號引入字元類別,以閉方括號結束。預設情況下,單獨的閉方括號沒有特殊意義。但是,如果設定了選項 PCRE_JAVASCRIPT_COMPAT
,則單獨的閉方括號會導致編譯時錯誤。如果需要將閉方括號作為類別的成員,則它必須是類別中的第一個資料字元 (如果存在初始脫字符號,則在該字元之後),或使用反斜線進行逸出。
字元類別會比對主體中的單個字元。在 UTF 模式下,該字元可以超過一個資料單元的長度。除非類別定義中的第一個字元是脫字符號,否則比對的字元必須在類別定義的字元集合中。在這種情況下,主體字元不得在類別定義的集合中。如果需要將脫字符號作為類別的成員,請確保它不是第一個字元,或使用反斜線逸出它。
例如,字元類別 [aeiou]
會比對任何小寫母音,而 [^aeiou]
會比對任何不是小寫母音的字元。請注意,脫字符號只是指定類別中字元的便捷表示法,方法是列舉不在其中的字元。以脫字符號開頭的類別不是斷言;它仍然會從主體字串中消耗一個字元,因此,如果目前的指標位於字串的末尾,則會失敗。
在 UTF-8 模式下,值 > 255 (0xffff) 的字元可以作為資料單元的文字字串包含在類別中,或使用 \x{
逸出機制。
當設定不區分大小寫的比對時,類別中的任何字母都表示其大寫和小寫版本。例如,不區分大小寫的 [aeiou]
會比對 "A" 和 "a",而不區分大小寫的 [^aeiou]
不會比對 "A",但區分大小寫的版本會比對。在 UTF 模式下,PCRE 始終會理解值 < 256 的字元的大小寫概念,因此始終可以進行不區分大小寫的比對。對於值較高的字元,只有在 PCRE 編譯時支援 Unicode 屬性時,才支援大小寫概念。如果要在 UTF 模式下對字元 >= 使用不區分大小寫的比對,請確保 PCRE 在編譯時支援 Unicode 屬性並且支援 UTF。
無論使用哪種行尾序列,以及使用選項 PCRE_DOTALL
和 PCRE_MULTILINE
的任何設定,在比對字元類別時,可以表示換行的字元永遠不會以任何特殊方式處理。諸如 [^a]
之類的類別始終會比對其中一個字元。
連字號 (hyphen) 字元可用於指定字元類別中的字元範圍。例如,[d-m]
會比對 d 和 m 之間 (含 d 和 m) 的任何字母。如果類別中需要連字號,則必須使用反斜線逸出它,或出現在不能解釋為表示範圍的位置,通常是類別中的第一個或最後一個字元,或緊接在範圍之後。例如,[b-d-z]
會比對範圍 b 到 d 中的字母、連字號或 z。
文字字元 "]" 不能是範圍的結束字元。諸如 [W-]46]
之類的模式會被解釋為包含兩個字元 ("W" 和 "-") 的類別,後跟文字字串 "46]",因此它會比對 "W46]" 或 "-46]"。但是,如果使用反斜線逸出 "]",它會被解釋為範圍的結尾,因此 [W-\]46]
會被解釋為包含一個範圍的類別,後跟另外兩個字元。也可以使用 "]" 的八進位或十六進位表示法來結束範圍。
如果 POSIX 字元類別 (請參閱下文) 或逸出序列 (除了定義單個字元的逸出序列之外) 出現在預期範圍結束字元的位置,則會產生錯誤。例如,[z-\xff]
有效,但 [A-\d]
和 [A-[:digit:]]
無效。
範圍在字元值的排序序列中運作。它們也可以用於以數字方式指定的字元,例如,[\000-\037]
。範圍可以包含對目前模式有效的所有字元。
如果在使用不區分大小寫比對時,使用了包含字母的範圍,則會比對該範圍內不論大小寫的字母。例如,[W-c]
等同於 [][\\^_`wxyzabc]
,且不區分大小寫比對。在非 UTF 模式下,如果使用法語地區的字元表,[\xc8-\xcb]
會比對大小寫的重音 E 字元。在 UTF 模式下,只有在編譯時啟用 Unicode 屬性支援時,PCRE 才會支援值大於 255 的字元的大小寫概念。
字元跳脫序列 \d
、\D
、\h
、\H
、\p
、\P
、\s
、\S
、\v
、\V
、\w
和 \W
可以出現在字元類別中,並將它們比對到的字元加入到該類別中。例如,[\dABCDEF]
會比對任何十六進位數字。在 UTF 模式下,選項 ucp
會影響 \d
、\s
、\w
及其大寫夥伴的含義,就像它們出現在字元類別之外時一樣,如同先前 通用字元類型 章節所述。跳脫序列 \b
在字元類別中具有不同的含義;它會比對退格字元。序列 \B
、\N
、\R
和 \X
在字元類別內並非特殊。它們會像任何其他無法識別的跳脫序列一樣,被視為字面字元 "B"、"N"、"R" 和 "X"。
插入符號可以方便地與大寫字元類型一起使用,以指定比比對小寫類型更受限的字元集。例如,類別 [^\W_]
比對任何字母或數字,但不包含底線,而 [\w]
則包含底線。正字元類別應讀作「某個東西 OR 某個東西 OR ...」,而負字元類別應讀作「非某個東西 AND 非某個東西 AND 非...」。
只有以下 meta 字元會在字元類別中被識別:
- 反斜線
- 連字號(僅在它可以被解釋為指定範圍時)
- 插入符號(僅在開頭)
- 左方括號(僅在它可以被解釋為引入 Posix 類別名稱時,或是為了特殊相容性功能;請參閱接下來的兩個章節)
- 終止右方括號
但是,跳脫其他非字母數字字元並無害處。
Posix 字元類別
Perl 支援 Posix 字元類別的表示法。此表示法使用以 [:
和 :]
括住的名稱,並置於外層方括號內。PCRE 也支援此表示法。例如,以下表示法比對 "0"、"1"、任何字母字元或 "%"
[01[:alpha:]%]
以下是支援的類別名稱:
alnum - 字母和數字
alpha - 字母
blank - 僅限空格或 Tab
cntrl - 控制字元
digit - 十進位數字(與
\d
相同)graph - 列印字元,不包含空格
lower - 小寫字母
print - 列印字元,包含空格
punct - 列印字元,不包含字母、數字和空格
space - 空白字元(與 PCRE 8.34 中的
\s
相同)upper - 大寫字母
word - 「單字」字元(與
\w
相同)xdigit - 十六進位數字
還有另一個字元類別 ascii
,它錯誤地比對 Latin-1 字元,而不是 POSIX 指定的 0-127 範圍。如果未變更其他類別的行為,則無法修正此問題,因此我們建議使用 [\\0-\x7f]
比對範圍。
預設的「空白」字元為 HT (9)、LF (10)、VT (11)、FF (12)、CR (13) 和空格 (32)。如果正在進行特定地區的比對,空白字元的清單可能會有所不同;它們可能會更少或更多。「空白」過去與 \s
不同,因為為了與 Perl 相容,它不包含 VT。然而,Perl 在 5.18 版中變更了此行為,PCRE 則在 8.34 版中跟進。「空白」和 \s
現在比對相同的字元集。
「單字」名稱是 Perl 的擴充功能,而「空白」是來自 Perl 5.8 的 GNU 擴充功能。另一個 Perl 擴充功能是否定,它由冒號後的 ^ 字元表示。例如,以下表示法比對 "1"、"2" 或任何非數字
[12[:^digit:]]
PCRE (和 Perl) 也會識別 Posix 語法 [.ch.]
和 [=ch=]
,其中 "ch" 是「校對元素」,但這些語法不受支援,如果遇到它們,則會給出錯誤。
預設情況下,值大於 255 的字元不會比對任何 Posix 字元類別。然而,如果將選項 PCRE_UCP
傳遞給 pcre_compile()
,某些類別會變更,以便使用 Unicode 字元屬性。這是透過將某些 Posix 類別替換為其他序列來實現,如下所示:
[:alnum:]
- 變成\p{Xan}
[:alpha:]
- 變成\p{L}
[:blank:]
- 變成\h
[:digit:]
- 變成\p{Nd}
[:lower:]
- 變成\p{Ll}
[:space:]
- 變成\p{Xps}
[:upper:]
- 變成\p{Lu}
[:word:]
- 變成\p{Xwd}
負版本,例如 [:^alpha:]
,會使用 \P
而不是 \p
。在 UCP 模式中,有另外三個 POSIX 類別會以特殊方式處理:
[:graph:]
- 此比對在列印時會標記頁面的字元。以 Unicode 屬性而言,它比對具有 L、M、N、P、S 或 Cf 屬性的所有字元,除了U+061C - 阿拉伯文字母標記
U+180E - 蒙古語母音分隔符號
U+2066 - U+2069 - 各種「隔離」字元
[:print:]
- 此比對與[:graph:]
相同的字元,再加上非控制的空白字元,也就是具有 Zs 屬性的字元。[:punct:]
- 此比對具有 Unicode P (標點符號) 屬性的所有字元,以及程式碼點小於 128 且具有 S (符號) 屬性的字元。
其他 POSIX 類別保持不變,並且只比對程式碼點小於 128 的字元。
單字邊界的相容性功能
在 4.4BSD Unix 中包含的符合 POSIX.2 標準的程式庫中,使用難看的語法 [[:<:]]
和 [[:>:]]
來比對「單字開頭」和「單字結尾」。PCRE 會將這些項目視為以下方式:
[[:<:]]
- 會轉換為\b(?=\w)
[[:>:]]
- 會轉換為\b(?<=\w)
只會識別這些確切的字元序列。例如 [a[:<:]b]
的序列會因為無法識別的 POSIX 類別名稱而引發錯誤。此支援與 Perl 不相容。提供此支援是為了協助從其他環境移轉,最好不要在任何新的模式中使用。請注意,\b
比對單字的開頭和結尾 (請參閱上方的「簡單斷言」),並且在 Perl 樣式的模式中,前一個或後一個字元通常會顯示想要比對的是哪個,而不需要使用上方為了提供精確 POSIX 行為所使用的斷言。
垂直線
垂直線字元用於分隔替代模式。例如,以下模式比對 "gilbert" 或 "sullivan":
gilbert|sullivan
可以出現任意數量的替代項,並且允許空替代項(比對空字串)。比對程序會從左到右依次嘗試每個替代項,並使用第一個成功的替代項。如果替代項位於子模式內(在 子模式 章節中定義),「成功」表示比對剩餘的主要模式和子模式中的替代項。
內部選項設定
Perl 相容選項 caseless
、multiline
、dotall
和 extended
的設定可以透過括在 "(?" 和 ")" 之間的 Perl 選項字母序列,從模式內變更。選項字母如下:
i - 代表
caseless
m - 代表
multiline
s - 代表
dotall
x - 代表
extended
例如,(?im)
設定不區分大小寫的多行比對。也可以透過在字母前面加上連字號來取消設定這些選項。也允許組合設定和取消設定,例如 (?im-sx)
,它會設定 caseless
和 multiline
,同時取消設定 dotall
和 extended
。如果字母同時出現在連字號之前和之後,則會取消設定該選項。
PCRE 特定的選項 dupnames
、ungreedy
和 extra
可以使用字元 J、U 和 X,以與 Perl 相容選項相同的方式變更。
當這些選項變更之一發生在頂層時(也就是不在子模式括號內),變更會套用至後面接續的剩餘模式。
子模式內的選項變更(請參閱 子模式 章節)只會影響該子模式中位於其後的部分。因此,以下內容會比對 abc 和 aBc,而不會比對其他字串(假設未使用 caseless
):
(a(?i)b)c
透過這種方式,可以使選項在模式的不同部分具有不同的設定。在一個替代項中所做的任何變更都會延續到同一個子模式內的後續分支。例如:
(a(?i)b|c)
比對 "ab"、"aB"、"c" 和 "C",儘管在比對 "C" 時,會在選項設定之前放棄第一個分支。這是因為選項設定的效果會在編譯時發生。否則會發生一些奇怪的行為。
注意
其他 PCRE 特定的選項可以由應用程式在呼叫編譯或比對函式時設定。有時,模式可以包含特殊的前導序列,例如 (*CRLF),以覆寫應用程式已設定或已預設的內容。詳細資訊請參閱先前 換行序列 章節。
前導序列 (UTF8) 和 (UCP) 可用於設定 UTF 和 Unicode 屬性模式。它們分別等同於設定選項
unicode
和ucp
。 (UTF) 序列是通用版本,可以用於任何程式庫。然而,應用程式可以設定選項never_utf
,這會鎖定 (UTF) 序列的使用。
子模式
子模式以括號(圓括號)分隔,並且可以巢狀。將模式的一部分變成子模式有兩個作用:
1. - 它會局部化一組選項。例如,以下模式會匹配 "cataract"、"caterpillar" 或 "cat"。
cat(aract|erpillar|)
如果沒有括號,它會匹配 "cataract"、"erpillar" 或空字串。
2. - 它將子模式設定為捕獲子模式。也就是說,當完整模式匹配時,與子模式匹配的主題字串部分會透過
run/3
的傳回值傳回給呼叫者。
左括號從左到右計數(從 1 開始),以取得捕獲子模式的編號。例如,如果字串 "the red king" 與以下模式匹配,則捕獲的子字串是 "red king"、"red" 和 "king",並且分別編號為 1、2 和 3。
the ((red|white) (king|queen))
單純的括號同時具有兩個功能,並不總是很有用。通常需要一個分組子模式,而不需要捕獲。如果左括號後面跟著問號和冒號,則子模式不會進行任何捕獲,並且在計算任何後續捕獲子模式的數量時不會被計算在內。例如,如果字串 "the white queen" 與以下模式匹配,則捕獲的子字串是 "white queen" 和 "queen",並且編號為 1 和 2。
the ((?:red|white) (king|queen))
捕獲子模式的最大數量為 65535。
作為一種方便的簡寫,如果需要在非捕獲子模式的開頭設定任何選項,則選項字母可以出現在 "?" 和 ":" 之間。因此,以下兩種模式匹配相同的字串集:
(?i:saturday|sunday)
(?:(?i)saturday|sunday)
由於替代分支是從左到右嘗試的,並且選項在到達子模式的結尾之前不會重設,因此一個分支中的選項設定會影響後續分支,因此上述模式會匹配 "SUNDAY" 和 "Saturday"。
重複的子模式編號
Perl 5.10 引入了一項功能,其中子模式中的每個替代方案都使用相同的編號作為其捕獲括號。這樣的子模式以 (?|
開頭,並且本身是非捕獲子模式。例如,考慮以下模式:
(?|(Sat)ur|(Sun))day
由於兩個替代方案都在 (?|
群組內,因此兩組捕獲括號都編號為 1。因此,當模式匹配時,您可以查看捕獲的子字串編號 1,無論哪個替代方案匹配。當您想要捕獲其中一個(但不是全部)替代方案的一部分時,此結構非常有用。在 (?|
群組內,括號會像往常一樣編號,但在每個分支的開頭會重設編號。任何跟在子模式之後的捕獲括號的編號,從任何分支中使用的最高編號之後開始。以下範例來自 Perl 文件;下方的數字顯示捕獲的內容儲存在哪個緩衝區中:
# before ---------------branch-reset----------- after
/ ( a ) (?| x ( y ) z | (p (q) r) | (t) u (v) ) ( z ) /x
# 1 2 2 3 2 3 4
對編號子模式的反向參考使用該編號的任何子模式所設定的最新值。以下模式會匹配 "abcabc" 或 "defdef"。
/(?|(abc)|(def))\1/
相反地,對編號子模式的子常式呼叫始終參考模式中具有給定編號的第一個子模式。以下模式會匹配 "abcabc" 或 "defabc"。
/(?|(abc)|(def))(?1)/
如果對子模式的匹配條件測試參考到非唯一的編號,則如果該編號的任何子模式匹配,則測試為 true。
使用此「分支重設」功能的另一種方法是使用重複的命名子模式,如下一節所述。
命名子模式
透過編號識別捕獲括號很簡單,但在複雜的正規表示式中追蹤編號可能會很困難。此外,如果修改了表示式,則編號可能會更改。為了協助解決這個困難,PCRE 支援子模式的命名。此功能直到 5.10 版本才新增到 Perl 中。Python 較早具有此功能,並且 PCRE 在 4.0 版本中引入了此功能,使用了 Python 語法。PCRE 現在同時支援 Perl 和 Python 語法。Perl 允許具有相同編號的子模式具有不同的名稱,但 PCRE 不允許。
在 PCRE 中,可以使用三種方式之一來命名子模式:(?<name>...)
或 (?'name'...)
,如 Perl 中所示,或 (?P<name>...)
,如 Python 中所示。從模式的其他部分(例如反向參考、遞迴和條件)對捕獲括號的參考,可以透過名稱和編號來進行。
名稱最多由 32 個字母數字字元和底線組成,但必須以非數字開頭。命名捕獲括號仍會分配編號和名稱,就像名稱不存在一樣。run/3
的 capture
規格可以使用正規表示式中存在的命名值。
預設情況下,名稱在模式中必須是唯一的,但是可以在編譯時透過設定選項 dupnames
來放寬此限制。(對於具有相同編號的子模式,也始終允許重複的名稱,如上一節所述設定。)在只有一個命名括號執行個體可以匹配的模式中,重複的名稱會很有用。假設您想要匹配星期幾的名稱,無論是 3 個字母的縮寫還是完整名稱,並且在這兩種情況下都想要擷取縮寫。以下模式(忽略換行符)可以完成這項工作:
(?<DN>Mon|Fri|Sun)(?:day)?|
(?<DN>Tue)(?:sday)?|
(?<DN>Wed)(?:nesday)?|
(?<DN>Thu)(?:rsday)?|
(?<DN>Sat)(?:urday)?
有五個捕獲子字串,但每次匹配後只會設定其中一個。(解決此問題的另一種方法是使用「分支重設」子模式,如上一節所述。)
對於名稱不唯一的捕獲命名子模式,如果 capture
陳述式的 values
部分指定了名稱,則會從 run/3
傳回第一個匹配的出現次數(從主題中的左到右計算)。all_names
捕獲值以相同方式匹配所有名稱。
注意
您不能使用不同的名稱來區分具有相同編號的兩個子模式,因為 PCRE 在匹配時僅使用編號。因此,如果在編譯時為具有相同編號的子模式指定不同的名稱,則會產生錯誤。但是,即使未設定
dupnames
,您也可以為具有相同編號的子模式指定相同的名稱。
重複
重複由量詞指定,量詞可以遵循以下任何項目:
- 文字資料字元
- 點元字元
\C
逸出序列\X
逸出序列\R
逸出序列- 與單一字元匹配的逸出,例如
\d
或\pL
- 字元類別
- 反向參考(請參閱下一節)
- 括號內的子模式(包括斷言)
- 對子模式的子常式呼叫(遞迴或其他方式)
一般重複量詞透過在大括號(花括號)中給定兩個數字(以逗號分隔)來指定允許匹配的最小和最大數量。數字必須 < 65536,並且第一個數字必須小於或等於第二個數字。例如,以下內容匹配 "zz"、"zzz" 或 "zzzz":
z{2,4}
單獨的右花括號不是特殊字元。如果省略第二個數字,但存在逗號,則沒有上限。如果省略第二個數字和逗號,則量詞指定所需匹配的確切數量。因此,以下內容至少匹配三個連續的母音,但可以匹配更多:
[aeiou]{3,}
以下內容完全匹配八個數字:
\d{8}
出現在不允許量詞的位置的花括號,或不符合量詞語法的花括號,被視為文字字元。例如,{,6} 不是量詞,而是由四個字元組成的文字字串。
在 Unicode 模式下,量詞適用於字元,而不是單個資料單位。因此,例如,\x{100}{2}
匹配兩個字元,每個字元在 UTF-8 字串中都由 2 個位元組序列表示。同樣,\X{3}
匹配三個 Unicode 擴充字形叢集,每個叢集都可以是多個資料單位長度(並且它們的長度可能不同)。
允許量詞 {0},這會使表示式的行為就像先前的項目和量詞不存在一樣。這對於從模式中的其他位置作為子常式參考的子模式會很有用(但也請參閱 僅供參考使用的定義子模式 區段)。具有 {0} 量詞的子模式以外的項目會從編譯的模式中省略。
為方便起見,三個最常見的量詞具有單字元縮寫:
* - 等效於 {0,}
+ - 等效於 {1,}
? - 等效於 {0,1}
可以透過在可以匹配零個字元的子模式之後加上沒有上限的量詞來建構無限迴圈,例如:
(a?)*
早期版本的 Perl 和 PCRE 會在編譯時針對此類模式產生錯誤。但是,由於在某些情況下這會很有用,因此現在接受此類模式。但是,如果子模式的任何重複匹配零個字元,則會強制中斷迴圈。
預設情況下,量詞是「貪婪的」,也就是說,它們會盡可能匹配(直到允許的最大次數),而不會導致其餘模式失敗。這會產生問題的經典範例是嘗試匹配 C 程式中的註解。這些註解出現在 / 和 / 之間。在註解中,可能會出現個別的 * 和 / 字元。嘗試透過應用模式來匹配 C 註解:
/\*.*\*/
到字串:
/* first comment */ not comment /* second comment */
失敗了,因為它由於 .* 項目的貪婪性而匹配了整個字串。
然而,如果量詞後面跟著問號,它就不再是貪婪的,而是匹配最少的可能次數,因此以下模式可以正確處理 C 語言的註解
/\*.*?\*/
各種量詞的意義並未改變,只是改變了偏好的匹配次數。請不要將問號的這種用法與其本身作為量詞的用法混淆。由於它有兩種用法,有時會出現重複的情況,例如
\d??\d
它偏好匹配一個數字,但如果這是剩餘模式匹配的唯一方法,則可以匹配兩個數字。
如果設定了 ungreedy
選項(此選項在 Perl 中不可用),量詞預設不是貪婪的,但可以通過在它們後面加上問號來使個別量詞變成貪婪的。也就是說,它反轉了預設行為。
當以最小重複次數 > 1 或有限最大值來量化括號內的子模式時,編譯後的模式需要更多記憶體,其量與最小或最大值的大小成正比。
如果模式以 .* 或 .{0,} 開頭,並且設定了 dotall
選項(等效於 Perl 選項 /s
),從而允許點號匹配換行符,則模式會被隱式錨定,因為後面的任何內容都會針對主體字串中的每個字元位置進行嘗試。因此,在第一個位置之後的任何位置重試整體匹配是沒有意義的。PCRE 通常將此類模式視為前面有 \A
。
在已知主體字串不包含換行符的情況下,值得設定 dotall
來獲得此最佳化,或者使用 ^ 來明確指示錨定。
但是,在某些情況下,無法使用最佳化。當 .* 在捕獲括號內,而該括號又是模式中其他地方的反向參照的主體時,開頭的匹配可能會失敗,而後面的匹配卻會成功。例如,請考慮
(.*)abc\1
如果主體是 "xyz123abc123",則匹配點是第四個字元。因此,此類模式不會隱式錨定。
不應用隱式錨定的另一種情況是,當開頭的 .* 在原子群組內時。同樣,開頭的匹配可能會失敗,而後面的匹配卻會成功。請考慮以下模式
(?>.*?a)b
它匹配主體 "aab" 中的 "ab"。使用回溯控制動詞(*PRUNE)和(*SKIP)也會停用此最佳化。
當重複捕獲子模式時,捕獲的值是匹配最後一次迭代的子字串。例如,在
(tweedle[dume]{3}\s*)+
匹配 "tweedledum tweedledee" 之後,捕獲的子字串的值是 "tweedledee"。但是,如果有巢狀的捕獲子模式,則相應的捕獲值可能已在先前的迭代中設定。例如,在
/(a|(b))+/
匹配 "aba" 之後,第二個捕獲的子字串的值是 "b"。
原子群組和佔有量詞
對於最大化(「貪婪」)和最小化(「非貪婪」或「惰性」)重複,如果後續內容失敗,通常會重新評估重複的項目,以查看不同的重複次數是否允許剩餘模式匹配。有時,防止這種情況是很有用的,可以改變匹配的性質,或者使其比原本可能的情況更早失敗,因為模式的作者知道繼續下去是沒有意義的。
例如,請考慮將模式 \d+foo
應用於以下主體行
123456bar
在匹配所有六個數字,然後未能匹配 "foo" 之後,匹配器的正常動作是嘗試只用五個數字匹配項目 \d+
,然後用四個數字,依此類推,最後才會失敗。「原子群組」(此術語取自 Jeffrey Friedl 的書)提供了一種方法,用於指定一旦子模式匹配,就不會以這種方式重新評估。
如果在先前的範例中使用原子群組,則匹配器會在第一次未能匹配 "foo" 時立即放棄。其表示法是一種特殊的括號,以 (?>
開頭,如下列範例所示
(?>\d+)foo
這種括號會在其中包含的模式部分匹配後「鎖定」它,並且防止模式中更深層次的失敗回溯到其中。然而,回溯到先前的項目,會像往常一樣工作。
另一種描述是,這種子模式匹配的字元串與在主體字串的當前點錨定的相同獨立模式將匹配的字元串相同。
原子群組子模式不是捕獲子模式。簡單的例子(例如上面的範例)可以被認為是必須吞下所有內容的最大化重複。因此,雖然 \d+
和 \d+?
都準備調整它們匹配的位數,以使剩餘模式匹配,但 (?>\d+)
只能匹配整個數字序列。
一般而言,原子群組可以包含任何複雜的子模式,並且可以巢狀。但是,當原子群組的子模式僅為單個重複項目時,如上例所示,可以使用更簡單的表示法,稱為「佔有量詞」。它由量詞後面的額外 + 字元組成。使用此表示法,先前的範例可以重寫為
\d++foo
請注意,佔有量詞可以用於整個群組,例如
(abc|xyz){2,3}+
佔有量詞始終是貪婪的;將忽略 ungreedy
選項的設定。它們是原子群組的更簡單形式的便利表示法。但是,佔有量詞和等效原子群組的含義沒有差異,但是效能上可能會有所差異;佔有量詞可能稍微快一些。
佔有量詞語法是對 Perl 5.8 語法的擴充。Jeffrey Friedl 在他的書的第一版中提出了這個想法(和名稱)。Mike McCloskey 喜歡它,因此他在建構 Sun Java 套件時實作了它,並且 PCRE 從那裡複製了它。它最終在 5.10 版本中進入了 Perl。
PCRE 具有一個最佳化,可以自動「佔有化」某些簡單的模式結構。例如,序列 A+B 被視為 A++B,因為當 B 必須跟隨時,回溯到 A 的序列中是沒有意義的。
當模式在本身可以重複無限次數的子模式內包含無限重複時,使用原子群組是避免某些失敗匹配耗費長時間的唯一方法。模式
(\D+|<\d+>)*[!?]
匹配無限數量的子字串,這些子字串由非數字或括在 <>
中的數字組成,後跟 !
或 ?
。當它匹配時,它會快速運行。但是,如果將其應用於
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
它需要很長時間才能報告失敗。這是因為字串可以在內部 \D+
重複和外部 * 重複之間以多種方式分割,並且必須嘗試所有方式。(範例使用 [!?]
而不是末尾的單個字元,因為 PCRE 和 Perl 都有一個最佳化,允許在使用單個字元時快速失敗。它們會記住匹配所需的最後一個單個字元,如果該字元不在字串中,則會提前失敗。)如果變更模式,使其使用原子群組(如下所示),則無法中斷非數字序列,並且會快速發生失敗
((?>\D+)|<\d+>)*[!?]
反向參照
在字元類別之外,反斜線後跟一個大於 0 的數字(並且可能還有更多數字)是對模式中較早(即在其左側)的捕獲子模式的反向參照,前提是之前存在那麼多捕獲的左括號。
但是,如果反斜線後面的十進制數字小於 10,則始終將其視為反向參照,並且僅當整個模式中沒有那麼多捕獲的左括號時才會導致錯誤。也就是說,被參照的括號不需要位於參照的左側,對於小於 10 的數字。當涉及重複時,這種型別的「前向反向參照」可能會有意義,並且右側的子模式已參與了較早的迭代。
使用此語法,不可能對編號為 10 或更大的子模式進行數字「前向反向參照」,因為 \50
之類的序列會被解釋為以八進制定義的字元。有關反斜線後面的數字處理的更多詳細資訊,請參閱前面的 非列印字元 一節。使用命名括號時,不存在此類問題。使用命名括號可以反向參照任何子模式(請參閱下文)。
避免反斜線後使用數字所固有的歧義的另一種方法是使用 \g
跳脫序列。此跳脫序列後面必須跟一個無符號數字或一個負數,可選擇用大括號括起來。以下範例相同
(ring), \1
(ring), \g1
(ring), \g{1}
無符號數字指定一個絕對參照,而不會像較舊語法中存在歧義。當文字數字跟在參照後面時,它也很有用。負數是相對參照。請考慮以下範例
(abc(def)ghi)\g{-1}
序列 \g{-1}
是對 \g
之前最近開始的捕獲子模式的參照,也就是說,在本範例中,它等效於 \2
。同樣,\g{-2}
將等效於 \1
。相對參照的使用在長模式中以及在通過連接包含自身內部參照的片段來建立的模式中可能很有幫助。
反向參照會比對目前主體字串中捕捉子模式所比對到的內容,而不是比對符合子模式的任何內容(子模式作為子常式章節描述了一種實現此目的的方法)。因此,以下模式會比對 "sense and sensibility" 和 "response and responsibility",但不會比對 "sense and responsibility"。
(sens|respons)e and \1ibility
如果在反向參照時強制執行區分大小寫比對,則字母的大小寫很重要。例如,以下模式會比對 "rah rah" 和 "RAH RAH",但不會比對 "RAH rah",儘管原始的捕捉子模式是不區分大小寫地比對的。
((?i)rah)\s+\1
有很多不同的方式可以撰寫對具名子模式的反向參照。.NET 語法 \k{name}
和 Perl 語法 \k<name>
或 \k'name'
都受支援,Python 語法 (?P=name)
也受支援。Perl 5.10 中統一的反向參照語法,其中 \g
可用於數值和具名參照,也受支援。先前的範例可以用以下方式重寫:
(?<p1>(?i)rah)\s+\k<p1>
(?'p1'(?i)rah)\s+\k{p1}
(?P<p1>(?i)rah)\s+(?P=p1)
(?<p1>(?i)rah)\s+\g{p1}
依名稱參照的子模式可以出現在參照之前或之後。
可以有多個對同一個子模式的反向參照。如果子模式在特定的比對中未使用,則對它的任何反向參照都會失敗。例如,如果以下模式開始比對 "a" 而不是 "bc",則該模式始終會失敗。
(a|(bc))\2
由於模式中可能有很多捕捉括號,因此反斜線後面的所有數字都會被視為潛在的反向參照數字的一部分。如果模式繼續使用數字字元,則必須使用分隔符號來終止反向參照。如果設定了 extended
選項,則可以使用空白字元。否則,可以使用空的註解(請參閱註解章節)。
遞迴反向參照
當子模式第一次被使用時,出現在它所參照的括號內的反向參照會失敗,因此,例如 (a\1
) 永遠不會比對。但是,這種參照在重複的子模式中可能很有用。例如,以下模式會比對任意數量的 "a" 以及 "aba"、"ababbaa" 等。
(a|b\1)+
在子模式的每次迭代中,反向參照會比對對應於前一次迭代的字元字串。為了使此功能起作用,模式必須如此,即第一次迭代不需要比對反向參照。這可以使用交替來完成,如上面的範例所示,或使用最小數量為零的量詞。
這種型別的反向參照會使其參照的群組被視為原子群組。一旦整個群組被比對,後續的比對失敗就不會導致回溯到群組的中間。
斷言
斷言是對目前比對點之後或之前的字元進行測試,而不會消耗任何字元。編碼為 \b
、\B
、\A
、\G
、\Z
、\z
、^
和 $
的簡單斷言在前面的章節中已說明。
更複雜的斷言被編碼為子模式。有兩種:一種是查看主體字串中目前位置之前的位置,另一種是查看其之後的位置。斷言子模式以正常方式比對,但不會導致目前比對位置被更改。
斷言子模式不是捕捉子模式。如果這樣的斷言包含其中的捕捉子模式,則會將這些子模式計入整個模式中捕捉子模式的編號。但是,子字串捕捉僅對正向斷言執行。(Perl 有時(但不總是)在負向斷言中執行捕捉。)
警告
如果包含一個或多個捕捉子模式的正向斷言成功,但稍後在模式中比對失敗導致回溯此斷言,則僅當未設定更高編號的捕捉時,才會重設斷言中的捕捉。不幸的是,這是目前實作的基本限制,而且由於 PCRE1 現在僅處於維護狀態,因此不太可能改變。
為了與 Perl 相容,可以重複斷言子模式。但是,多次斷言同一件事沒有意義,捕捉括號的副作用偶爾會很有用。實際上,只有三種情況:
- 如果量詞是 {0},則在比對期間永遠不會遵守斷言。但是,它可以包含從其他地方透過子常式機制呼叫的內部捕捉括號群組。
- 如果量詞是 {0,n},其中 n > 0,則將其視為 {0,1}。在執行階段,會嘗試使用和不使用斷言來比對剩餘的模式,順序取決於量詞的貪婪度。
- 如果最小重複次數 > 0,則會忽略量詞。斷言僅在比對期間遇到時遵守一次。
前瞻斷言
前瞻斷言以 (?= 表示正向斷言,以 (?! 表示負向斷言。例如,以下模式會比對後跟分號的單字,但不將分號包含在比對中:
\w+(?=;)
以下模式會比對任何未後跟 "bar" 的 "foo" 的出現:
foo(?!bar)
請注意,明顯相似的模式:
(?!foo)bar
並未找到以 "foo" 以外的內容開頭的 "bar" 出現。它找到任何 "bar" 的出現,因為當接下來的三個字元是 "bar" 時,斷言 (?!foo) 始終為 true。需要後顧斷言才能實現另一個效果。
如果您想強制在模式中的某個點發生比對失敗,最方便的方法是使用 (?!),因為空字串始終會比對。因此,要求不存在空字串的斷言必須始終失敗。回溯控制動詞 (FAIL) 或 (F) 是 (?! 的同義詞。
後顧斷言
後顧斷言以 (?<= 表示正向斷言,以 (?
(?<!foo)bar
後顧斷言的內容受到限制,因此它所比對的所有字串都必須具有固定長度。但是,如果存在許多最上層替代方案,則它們不必都具有相同的固定長度。因此,允許使用以下方式:
(?<=bullock|donkey)
以下情況會在編譯時導致錯誤:
(?<!dogs?|cats?)
僅允許在後顧斷言的最上層使用比對不同長度字串的分支。與 Perl 相比,這是一個擴展,Perl 要求所有分支都比對相同長度的字串。不允許使用諸如以下的斷言,因為其單個最上層分支可以比對兩個不同的長度:
(?<=ab(c|de))
但是,如果將其重寫為使用兩個最上層分支,則 PCRE 可以接受:
(?<=abc|abde)
有時可以使用跳脫序列 \K
(如上所述)來代替後顧斷言以繞過固定長度的限制。
後顧斷言的實作是,對於每個替代方案,將目前位置暫時向後移動固定長度,然後嘗試比對。如果目前位置之前沒有足夠的字元,則斷言會失敗。
在 UTF 模式下,PCRE 不允許 \C
跳脫(即使在 UTF 模式下也比對單個資料單元)出現在後顧斷言中,因為這樣就無法計算後顧的長度。\X
和 \R
跳脫(可以比對不同數量的資料單元)也不允許使用。
"子常式" 呼叫(請參閱下文),例如 (?2) 或 (?&X),允許在後顧中使用,前提是子模式比對固定長度的字串。但是,不支援遞迴。
佔有量詞可以與後顧斷言一起使用,以指定在主體字串末尾高效比對固定長度的字串。將以下簡單模式套用至不符合的長字串時,請考量:
abcd$
由於比對從左到右進行,因此 PCRE 會尋找主體中的每個 "a",然後查看後面的內容是否符合剩餘模式。如果模式指定為:
^.*abcd$
則最初的 .* 會比對整個字串。但是,當此失敗時(因為沒有後續的 "a"),它會回溯以比對除最後一個字元外的所有字元,然後比對除最後兩個字元外的所有字元,依此類推。再次搜尋 "a" 會涵蓋整個字串(從右到左),因此我們沒有變得更好。但是,如果模式寫成:
^.*+(?<=abcd)
則 .*+ 項目不能回溯;它只能比對整個字串。後續的後顧斷言會對最後四個字元執行單一測試。如果失敗,則比對立即失敗。對於長字串,此方法會顯著影響處理時間。
使用多個斷言
可以連續出現許多斷言(任何類型)。例如,以下模式會比對以三個非 "999" 的數字開頭的 "foo":
(?<=\d{3})(?<!999)foo
請注意,每個斷言都會在主體字串中的同一個點獨立應用。首先會檢查前三個字元是否都是數字,然後檢查相同的三個字元是否不是 "999"。此模式 * 不 * 會比對以六個字元開頭的 "foo",其中前三個是數字,最後三個不是 "999"。例如,它不比對 "123abcfoo"。執行此操作的模式如下:
(?<=\d{3}...)(?<!999)foo
這次,第一個斷言會查看前面的六個字元,檢查前三個是否是數字,然後第二個斷言會檢查前面的三個字元是否不是 "999"。
斷言可以以任何組合嵌套。例如,以下模式會比對以 "bar" 開頭的 "baz" 的出現,而 "bar" 又不是以 "foo" 開頭:
(?<=(?<!foo)bar)baz
以下模式會比對以三個數字和任意三個不是 "999" 的字元開頭的 "foo":
(?<=\d{3}(?!999)...)foo
條件子模式
可以根據斷言的結果,或是否已比對特定的捕捉子模式,使比對程序有條件地遵循子模式或在兩個替代子模式之間進行選擇。以下是條件子模式的兩種可能形式:
(?(condition)yes-pattern)
(?(condition)yes-pattern|no-pattern)
如果滿足條件,則使用 yes-pattern,否則使用 no-pattern(如果存在)。如果子模式中存在兩個以上的替代方案,則會發生編譯時錯誤。兩個替代方案中的每一個都可能包含任何形式的嵌套子模式,包括條件子模式;對兩個替代方案的限制僅適用於條件的層級。以下模式片段是一個範例,其中替代方案很複雜:
(?(1) (A|B|C) | (D | (?(2)E|F) | E) )
有四種類型的條件:對子模式的參照、對遞迴的參照、稱為 DEFINE 的虛擬條件和斷言。
依編號檢查已使用的子模式
如果括號內的文字是一連串的數字,則當該數字的捕獲子模式先前已匹配時,條件為真。如果存在多個具有相同編號的捕獲子模式(請參閱先前的 重複的子模式編號 章節),則當其中任何一個匹配時,條件為真。另一種表示法是在數字前面加上加號或減號。在這種情況下,子模式編號是相對的而不是絕對的。最近開啟的括號可以使用 (?(-1) 來引用,倒數第二個最近開啟的括號可以使用 (?(-2) 來引用,依此類推。在迴圈內,也可以引用後續的群組。下一個要開啟的括號可以使用 (?(+1) 來引用,依此類推。(在任何這些形式中,值零都不使用;它會引發編譯時錯誤。)
考慮以下模式,其中包含非必要的空白符號,使其更易於閱讀(假設選項 extended
)並將其分為三個部分,以便於討論
( \( )? [^()]+ (?(1) \) )
第一部分匹配一個可選的左括號,如果該字元存在,則將其設定為第一個捕獲的子字串。第二部分匹配一個或多個不是括號的字元。第三部分是一個條件子模式,它測試第一組括號是否匹配。如果它們匹配,也就是說,如果主體以左括號開頭,則條件為真,因此執行 yes-pattern 並需要一個右括號。否則,由於 no-pattern 不存在,因此子模式不匹配任何內容。也就是說,此模式匹配一個非括號的序列,可選擇用括號括起來。
如果此模式嵌入到較大的模式中,則可以使用相對引用
...other stuff... ( \( )? [^()]+ (?(-1) \) ) ...
這使得該片段獨立於較大模式中的括號。
依名稱檢查已使用的子模式
Perl 使用語法 (?(<name>)...) 或 (?('name')...) 來依名稱測試已使用的子模式。為了與早期版本的 PCRE 相容(在 Perl 之前就有此功能),語法 (?(name)...) 也被識別。
將先前的範例重寫為使用具名子模式,結果如下
(?<OPEN> \( )? [^()]+ (?(<OPEN>) \) )
如果此類條件中使用的名稱是重複的,則測試將應用於所有具有相同名稱的子模式,並且當其中任何一個匹配時,結果為真。
檢查模式遞迴
如果條件是字串 (R),並且沒有名稱為 R 的子模式,則當對整個模式或任何子模式進行遞迴呼叫時,條件為真。如果字母 R 後面跟著數字或以 & 符號開頭的名稱,例如
(?(R3)...) or (?(R&name)...)
則當最近的遞迴是進入到指定編號或名稱的子模式時,條件為真。此條件不會檢查整個遞迴堆疊。如果此類條件中使用的名稱是重複的,則測試將應用於所有具有相同名稱的子模式,並且當其中任何一個是最近的遞迴時,結果為真。
在「頂層」,所有這些遞迴測試條件都為假。遞迴模式的語法在下面描述。
定義僅供參考使用的子模式
如果條件是字串 (DEFINE),並且沒有名稱為 DEFINE 的子模式,則條件始終為假。在這種情況下,子模式中只能有一個替代方案。如果控制到達模式中的這一點,它始終會被跳過。DEFINE 的想法是它可以被用來定義可以從其他地方參考的「子程式」。 (子程式的使用方法在下面描述。) 例如,匹配 IPv4 位址(例如「192.168.23.245」)的模式可以這樣寫(忽略空白符號和換行符號)
(?(DEFINE) (?<byte> 2[0-4]\d | 25[0-5] | 1\d\d | [1-9]?\d) ) \b (?&byte) (\.(?&byte)){3} \b
模式的第一部分是一個 DEFINE 群組,其中定義了另一個名為「byte」的群組。這匹配 IPv4 位址的單個組成部分(一個小於 256 的數字)。當進行匹配時,模式的這一部分會被跳過,因為 DEFINE 的作用類似於一個假條件。其餘模式使用對具名群組的引用來匹配 IPv4 位址的四個以點分隔的組成部分,並堅持在每一端的字詞邊界。
斷言條件
如果條件不屬於上述任何格式,則它必須是斷言。這可以是正向或負向先行斷言或後行斷言。考慮以下模式,其中包含非必要的空白符號,並且第二行上有兩種替代方案
(?(?=[^a-z]*[a-z])
\d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} )
該條件是一個正向先行斷言,它匹配一個可選的非字母序列,後面跟著一個字母。也就是說,它測試主體中是否存在至少一個字母。如果找到字母,則主體與第一個替代方案匹配,否則與第二個替代方案匹配。此模式匹配以下兩種形式之一的字串 dd-aaa-dd 或 dd-dd-dd,其中 aaa 是字母,dd 是數字。
註解
有兩種方法可以在 PCRE 處理的模式中包含註解。在這兩種情況下,註解的開頭都不能在字元類別中,或者在任何其他相關字元序列的中間,例如 (?: 或子模式名稱或編號。構成註解的字元在模式匹配中不起任何作用。
序列 (?# 標記註解的開始,該註解將持續到下一個右括號。不允許使用巢狀括號。如果設定了選項 PCRE_EXTENDED,則未轉義的 # 字元也會引入註解,在這種情況下,註解將持續到模式中下一個換行字元或字元序列之後。哪些字元被解釋為換行符號由傳遞給編譯函數的選項或模式開頭的特殊序列控制,如先前的 換行符號慣例 章節所述。
請注意,這種註解的結尾是模式中的文字換行序列;碰巧表示換行的跳脫序列不算數。例如,當 extended
設定時,並且強制執行預設換行符號慣例時,請考慮以下模式
abc #comment \n still comment
當遇到字元 # 時,pcre_compile()
會跳過,在模式中尋找換行符號。序列 \n
在這個階段仍然是文字,因此它不會終止註解。只有程式碼值為 0x0a 的字元(預設換行符號)才會終止註解。
遞迴模式
考慮匹配括號內的字串的問題,允許無限巢狀括號。如果不使用遞迴,則最佳方法是使用匹配到某個固定巢狀深度的模式。無法處理任意的巢狀深度。
一段時間以來,Perl 提供了一種允許正規表示式遞迴的功能(除此之外)。它是透過在執行階段在表示式中插入 Perl 程式碼來實現的,並且程式碼可以引用表示式本身。可以使用程式碼插入來建立 Perl 模式以解決括號問題,如下所示
$re = qr{\( (?: (?>[^()]+) | (?p{$re}) )* \)}x;
項目 (?p{...}) 在執行階段插入 Perl 程式碼,在這種情況下,會遞迴地引用它出現的模式。
顯然,PCRE 無法支援插入 Perl 程式碼。相反,它支援用於整個模式遞迴和個別子模式遞迴的特殊語法。在 PCRE 和 Python 中引入此類遞迴之後,這種遞迴後來在 5.10 版中引入到 Perl。
由 (? 後面跟著大於 0 的數字和右括號組成的特殊項目是給定編號的子模式的遞迴子程式呼叫,如果它發生在該子模式內。(如果不是,則它是非遞迴子程式呼叫,這將在下一節中描述。)特殊項目 (?R) 或 (?0) 是對整個正規表示式的遞迴呼叫。
此 PCRE 模式解決了巢狀括號問題(假設已設定選項 extended
,以便忽略空白符號)
\( ( [^()]++ | (?R) )* \)
首先它匹配一個左括號。然後它匹配任意數量的子字串,這些子字串可以是沒有括號的序列或模式本身的遞迴匹配(即,正確括起來的子字串)。最後是一個右括號。請注意,使用了佔有量詞來避免回溯到非括號序列。
如果這是較大模式的一部分,您將不希望遞迴整個模式,因此您可以改用
( \( ( [^()]++ | (?1) )* \) )
此處模式位於括號內,以便遞迴引用它們而不是整個模式。
在較大的模式中,追蹤括號編號可能很棘手。使用相對引用可以更輕鬆地完成此操作。您可以使用 (?-2) 來引用遞迴之前的倒數第二個最近開啟的括號,而不是上述模式中的 (?1)。也就是說,負數從遇到它的點開始向左計算捕獲括號。
也可以透過寫入 (?+2) 之類的引用來引用稍後開啟的括號。但是,這些不能是遞迴的,因為引用不在被引用的括號內。它們始終是非遞迴子程式呼叫,如下一節所述。
另一種方法是改用具名括號。Perl 的語法是 (?&name)。也支援早期的 PCRE 語法 (?P>name)。我們可以將上面的範例重寫如下
(?<pn> \( ( [^()]++ | (?&pn) )* \) )
如果有多個具有相同名稱的子模式,則使用最早的子模式。
我們研究的這個特殊範例模式包含巢狀無限重複,因此當將模式應用於不匹配的字串時,使用佔有量詞來匹配非括號的字串非常重要。例如,當此模式應用於
(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()
時,它會快速產生「不匹配」。但是,如果不使用佔有量詞,則匹配會執行很長時間,因為 + 和 * 重複有很多不同的方法可以劃分主體,並且在報告失敗之前必須測試所有方法。
在匹配結束時,捕獲括號的值是來自最外層的值。如果上面的模式與
(ab(cd)ef)
匹配,則內部捕獲括號(編號為 2)的值為「ef」,這是頂層最後採用的值。如果捕獲子模式在頂層不匹配,則其最終捕獲的值將不設定,即使它在匹配過程中在較深的層級(暫時)設定了。
不要將項目 (?R) 與條件 (R) 混淆,後者會測試遞迴。考慮以下模式,該模式匹配角括號內的文字,允許任意巢狀。巢狀括號(即,當遞迴時)中僅允許使用數字,而任何字元都可以在外層使用。
< (?: (?(R) \d++ | [^<>]*+) | (?R)) * >
此處 (?(R) 是條件子模式的開始,對於遞迴和非遞迴情況有兩種不同的替代方案。項目 (?R) 是實際的遞迴呼叫。
PCRE 和 Perl 之間遞迴處理的差異
PCRE 中的遞迴處理在兩個重要方面與 Perl 不同。在 PCRE 中(與 Python 類似,但與 Perl 不同),遞迴子模式呼叫始終被視為原子群組。也就是說,一旦它匹配了主體字串的一部分,即使它包含未嘗試的替代方案,並且後續出現匹配失敗,它也不會再重新進入。以下模式可以說明這一點,該模式旨在匹配包含奇數個字元的迴文(例如,「a」、「aba」、「abcba」、「abcdcba」)
^(.|(.)(?1)\2)$
這個概念是,它要么匹配單個字元,要么匹配環繞子迴文的兩個相同字元。在 Perl 中,這個模式有效;在 PCRE 中,如果模式長度超過三個字元,則無效。考慮主體字串「abcba」。
在頂層,第一個字元被匹配,但由於它不在字串的結尾,因此第一個替代方案失敗,採用第二個替代方案,並開始遞迴。對子模式 1 的遞迴呼叫成功匹配下一個字元(「b」)。(請注意,行首和行尾的測試不屬於遞迴的一部分。)
回到頂層,下一個字元(「c」)與子模式 2 匹配的字元(即「a」)進行比較。這會失敗。由於遞迴被視為原子群組,因此現在沒有回溯點,因此整個匹配失敗。(Perl 現在可以重新進入遞迴並嘗試第二個替代方案。)但是,如果模式以相反的順序寫出替代方案,情況就會不同
^((.)(?1)\2|.)$
這次,首先嘗試遞迴替代方案,並繼續遞迴,直到字元耗盡,此時遞迴失敗。但這次我們在較高層次有另一個替代方案可嘗試。這就是顯著的差異:在前一種情況下,剩餘的替代方案位於較深的遞迴層次,而 PCRE 無法使用它。
要變更模式使其匹配所有迴文字串,而不僅僅是那些具有奇數個字元的字串,很自然地會將模式變更為這樣
^((.)(?1)\2|.?)$
同樣,這在 Perl 中有效,但在 PCRE 中無效,原因相同。當較深的遞迴匹配單個字元時,它不能再次進入以匹配空字串。解決方案是分離這兩種情況,並將奇數和偶數情況寫為較高層次的替代方案
^(?:((.)(?1)\2|)|((.)(?3)\4|.))
如果要匹配典型的迴文短語,該模式必須忽略所有非文字字元,可以按如下方式完成
^\W*+(?:((.)\W*+(?1)\W*+\2|)|((.)\W*+(?3)\W*+\4|\W*+.\W*+))\W*+$
如果使用 caseless
選項執行,此模式會匹配諸如「A man, a plan, a canal: Panama!」之類的短語,並且在 PCRE 和 Perl 中都能正常運作。請注意使用佔有量詞 *+ 以避免回溯到非文字字元序列中。如果沒有這個,PCRE 需要更長的時間(10 倍或更多)來匹配典型的短語,而 Perl 需要很長時間,以至於您會認為它進入了迴圈。
注意
只有當主體字串不是以比整個字串短的迴文開頭時,上面的迴文匹配模式才有效。例如,雖然「abcba」被正確匹配,但如果主體是「ababa」,則 PCRE 會在開頭找到迴文「aba」,然後在頂層失敗,因為字串結尾沒有跟隨。再次,它無法跳回遞迴以嘗試其他替代方案,因此整個匹配失敗。
PCRE 和 Perl 在遞迴處理方面的第二個區別在於對捕獲值的處理。在 Perl 中,當子模式以遞迴方式或作為子模式呼叫時(請參閱下一節),它無法存取在遞迴外部捕獲的任何值。在 PCRE 中,可以參考這些值。考慮以下模式
^(.)(\1|a(?2))
在 PCRE 中,它匹配「bab」。第一個捕獲括號匹配「b」,然後在第二個群組中,當反向參考 \1
無法匹配「b」時,第二個替代方案匹配「a」,然後遞迴。在遞迴中,\1
現在匹配「b」,因此整個匹配成功。在 Perl 中,模式無法匹配,因為在遞迴呼叫內部,\1
無法存取外部設定的值。
子模式作為子常式
如果在它所引用的括號之外使用遞迴子模式呼叫(按編號或名稱)的語法,它的運作方式就像程式語言中的子常式。被呼叫的子模式可以在參考之前或之後定義。編號參考可以是絕對的或相對的,如下列範例所示
(...(absolute)...)...(?2)...
(...(relative)...)...(?-1)...
(...(?+1)...(relative)...
較早的範例指出,以下模式匹配「sense and sensibility」和「response and responsibility」,但不匹配「sense and responsibility」
(sens|respons)e and \1ibility
如果改為使用以下模式,它將匹配「sense and responsibility」和其他兩個字串
(sens|respons)e and (?1)ibility
在稍早對 DEFINE 的討論中提供了另一個範例。
所有子常式呼叫,無論是否為遞迴,始終被視為原子群組。也就是說,一旦子常式匹配了主體字串的一部分,即使它包含未嘗試的替代方案,並且後續出現匹配失敗,它也不會再重新進入。在子常式呼叫期間設定的任何捕獲括號都會在之後還原為先前的值。
在定義子模式時,會固定諸如區分大小寫之類的處理選項,因此如果將其用作子常式,則無法針對不同的呼叫變更此類選項。例如,以下模式匹配「abcabc」但不匹配「abcABC」,因為處理選項的變更不會影響被呼叫的子模式
(abc)(?i:(?-1))
Oniguruma 子常式語法
為了與 Oniguruma 相容,非 Perl 語法 \g
後面接著以角括號或單引號括起來的名稱或數字,是將子模式作為子常式(可能是遞迴)參考的替代語法。以下是使用此語法重寫的上述兩個範例
(?<pn> \( ( (?>[^()]+) | \g<pn> )* \) )
(sens|respons)e and \g'1'ibility
PCRE 支援 Oniguruma 的擴充功能:如果數字前面帶有加號或減號,則將其視為相對參考,例如
(abc)(?i:\g<-1>)
請注意,\g{...}
(Perl 語法) 和 \g<...>
(Oniguruma 語法) 並不同義。前者是反向參考;後者是子常式呼叫。
回溯控制
Perl 5.10 引入了一些「特殊回溯控制動詞」,這些動詞在 Perl 文件中仍然被描述為「實驗性的,並可能在未來的 Perl 版本中變更或移除」。它繼續說:「應記錄其在生產程式碼中的使用,以避免升級期間出現問題。」相同的評論適用於本節中描述的 PCRE 功能。
新的動詞利用了先前無效的語法:左括號後面跟著星號。它們通常採用 (VERB) 或 (VERB:NAME) 的形式。有些可以採用兩種形式,可能會根據是否存在名稱而表現不同。名稱是任何不包含右括號的字元序列。在 8 位元程式庫中,最大名稱長度為 255,在 16 位元和 32 位元程式庫中,最大名稱長度為 65535。如果名稱為空,也就是說,如果右括號緊跟在冒號之後,則其效果如同冒號不存在一樣。這些動詞可以在模式中出現任意次數。
這些動詞在重複群組、斷言以及作為子常式(無論是否為遞迴)呼叫的子模式中的行為將在下面描述。
影響回溯動詞的最佳化
PCRE 包含一些最佳化,這些最佳化用於透過在每次嘗試匹配開始時執行一些檢查來加速匹配。例如,它可以知道匹配主體的最小長度,或者必須存在特定字元。當其中一種最佳化繞過匹配的執行時,任何包含的回溯動詞都不會被處理。您可以透過在呼叫 compile/2
或 run/3
時設定選項 no_start_optimize
,或以 (*NO_START_OPT) 開頭模式來抑制匹配開始的最佳化。
對 Perl 的實驗表明,它也有類似的最佳化,有時會導致異常的結果。
立即生效的動詞
以下動詞在遇到時立即生效。它們後面不能跟隨名稱。
(*ACCEPT)
此動詞會導致匹配成功結束,跳過模式的其餘部分。但是,當它位於作為子常式呼叫的子模式內部時,只有該子模式才會成功結束。然後,匹配會在外部層次繼續。如果在肯定斷言中觸發 (*ACCEPT),則斷言成功;在否定斷言中,斷言失敗。
如果 (*ACCEPT) 位於捕獲括號內,則會捕獲到目前為止的資料。例如,以下模式匹配「AB」、「AAD」或「ACD」。當它匹配「AB」時,「B」會被外部括號捕獲。
A((?:A|B(*ACCEPT)|C)D)
以下動詞會導致匹配失敗,強制執行回溯。它等效於 (?!) 但更易於閱讀。
(*FAIL) or (*F)
Perl 文件指出,它可能僅在與 (?{}) 或 (??{}) 結合使用時有用。這些是 PCRE 中不存在的 Perl 功能。
與字串「aaaa」的匹配始終會失敗,但在每次回溯發生之前都會進行呼叫(在此範例中,進行 10 次)。
記錄所採取的路徑
此動詞的主要目的是追蹤匹配是如何實現的,儘管它在推進匹配起點方面也有次要用途(請參閱下面的 (*SKIP))。
注意
在 Erlang 中,沒有介面可以使用
run/2,3
擷取標記,因此只有次要目的與 Erlang 程式設計師相關。因此,本節的其餘部分刻意不針對 Erlang 程式設計師閱讀進行改編,但範例可以幫助理解 NAME,因為它們可以被 (*SKIP) 使用。
(*MARK:NAME) or (*:NAME)
此動詞始終需要一個名稱。在模式中可以存在任意多個 (*MARK) 執行個體,並且它們的名稱不必唯一。
當匹配成功時,匹配路徑上遇到的最後一個 (MARK:NAME)、(PRUNE:NAME) 或 (*THEN:NAME) 的名稱會傳回給呼叫者,如 pcreapi
文件中「pcre_exec()
的額外資料」一節所述。在以下 pcretest
輸出範例中,/K 修飾符請求擷取和輸出 (*MARK) 資料
re> /X(*MARK:A)Y|X(*MARK:B)Z/K
data> XY
0: XY
MK: A
XZ
0: XZ
MK: B
(*MARK) 名稱在此輸出中標記為「MK:」,在此範例中,它指示匹配了兩個替代方案中的哪一個。這是獲取此資訊的一種更有效方式,而不是將每個替代方案放入其自己的捕獲括號中。
如果在為真的肯定斷言中遇到帶有名稱的動詞,則會記錄該名稱,並且如果它是最後遇到的名稱,則會傳回該名稱。這不會發生在否定斷言或失敗的肯定斷言中。
在部分匹配或失敗的匹配之後,會傳回整個匹配過程中遇到的最後一個名稱,例如
re> /X(*MARK:A)Y|X(*MARK:B)Z/K
data> XP
No match, mark = B
請注意,在此未錨定的範例中,標記會保留自主體中字母「X」開始的匹配嘗試中。後續從「P」開始,然後使用空字串開始的匹配嘗試不會到達 (*MARK) 項目,但不會重設它。
回溯後生效的動詞
當遇到以下動詞時,它們不會執行任何動作。匹配會繼續進行後續的內容,但如果後續沒有匹配項,導致回溯到該動詞,則會強制失敗。也就是說,回溯不能通過動詞的左側。然而,當這些動詞之一出現在原子群組或為真的斷言中時,其效果會被限制在該群組內,因為一旦群組被匹配,就永遠不會再回溯到其中。在這種情況下,回溯可以「跳回」到整個原子群組或斷言的左側。(還請記住,如上所述,此本地化也適用於子程式呼叫。)
這些動詞的區別在於,當回溯到達它們時,具體會發生哪種失敗。以下描述的行為是在動詞不在子程式或斷言中時發生的情況。後續章節會涵蓋這些特殊情況。
如果後續的匹配失敗導致回溯到達以下動詞(其後不得跟隨名稱),則會導致整個匹配徹底失敗。即使模式沒有錨定,也不會再嘗試通過推進起點來尋找匹配項。
(*COMMIT)
如果 (*COMMIT) 是唯一遇到的回溯動詞,一旦它被通過,run/2,3
會被承諾在當前起點尋找匹配項,或者根本不尋找,例如
a+(*COMMIT)b
這會匹配 "xxaab",但不會匹配 "aacaab"。它可以被認為是一種動態錨點,或是「我已經開始了,所以我必須完成」。當 (*COMMIT) 強制匹配失敗時,會傳回路徑中最近通過的 (MARK) 的名稱。
如果模式中存在多個回溯動詞,則可以先觸發 (*COMMIT) 之後的不同動詞,因此僅在匹配期間通過 (*COMMIT) 並不總是保證必須在此起點進行匹配。
請注意,模式開頭的 (*COMMIT) 與錨點不同,除非關閉 PCRE 的匹配開始最佳化功能,如下例所示
1> re:run("xyzabc","(*COMMIT)abc",[{capture,all,list}]).
{match,["abc"]}
2> re:run("xyzabc","(*COMMIT)abc",[{capture,all,list},no_start_optimize]).
nomatch
對於此模式,PCRE 知道任何匹配都必須以 "a" 開頭,因此最佳化會沿著主體跳到 "a",然後將模式應用於第一組資料。然後匹配嘗試成功。在第二次呼叫中,no_start_optimize
停用了跳到第一個字元的最佳化功能。現在從 "x" 開始應用模式,因此 (*COMMIT) 會導致匹配失敗,而不會嘗試任何其他起點。
如果後續的匹配失敗導致回溯到達以下動詞,則會導致在主體的當前起始位置匹配失敗
(*PRUNE) or (*PRUNE:NAME)
如果模式未錨定,則會發生正常的「bumpalong」推進到下一個起始字元。在到達 (PRUNE) 之前,或是在匹配到 (PRUNE) 右側時,可以像往常一樣發生回溯,但如果右側沒有匹配項,則回溯不能跨越 (PRUNE)。在簡單情況下,使用 (PRUNE) 只是原子群組或佔有式量詞的替代方案,但 (PRUNE) 的某些用途無法以任何其他方式表達。在錨定模式中,(PRUNE) 的效果與 (*COMMIT) 相同。
(*PRUNE:NAME) 的行為與 (MARK:NAME)(PRUNE) 不同。它類似於 (*MARK:NAME),因為名稱會被記住,以便傳回給呼叫者。然而,(*SKIP:NAME) 只會搜尋使用 (*MARK) 設定的名稱。
注意
事實上,(*PRUNE:NAME) 會記住名稱,這對 Erlang 程式設計師來說沒有用處,因為無法檢索名稱。
以下動詞在未指定名稱時,類似於 (PRUNE),只是如果模式未錨定,「bumpalong」推進不是到下一個字元,而是到主體中遇到 (SKIP) 的位置。
(*SKIP)
(*SKIP) 表示在成功匹配之前匹配的任何文字都不能成為成功匹配的一部分。考慮
a+(*SKIP)b
如果主體是 "aaaac...",則在第一次匹配嘗試失敗後(從字串中的第一個字元開始),起點會跳到 "c" 開始下一次嘗試。請注意,佔有式量詞與此範例的效果不同;儘管它會在第一次匹配嘗試期間抑制回溯,但第二次嘗試會從第二個字元開始,而不是跳到 "c"。
當 (*SKIP) 具有關聯的名稱時,其行為會被修改
(*SKIP:NAME)
當觸發此操作時,會在模式中搜尋先前的路徑,以尋找具有相同名稱的最近 (MARK)。如果找到一個,則「bumpalong」推進會到達與該 (MARK) 對應的主體位置,而不是到達遇到 (*SKIP) 的位置。如果找不到具有匹配名稱的 (MARK),則會忽略 (SKIP)。
請注意,(*SKIP:NAME) 只會搜尋由 (*MARK:NAME) 設定的名稱。它會忽略由 (*PRUNE:NAME) 或 (*THEN:NAME) 設定的名稱。
以下動詞會在回溯到達它時,導致跳到下一個最內層的替代方案。也就是說,它會取消目前替代方案中的任何進一步回溯。
(*THEN) or (*THEN:NAME)
動詞名稱來自觀察,它可以被用於基於模式的 if-then-else 區塊
( COND1 (*THEN) FOO | COND2 (*THEN) BAR | COND3 (*THEN) BAZ ) ...
如果 COND1 模式匹配,則會嘗試 FOO(如果 FOO 成功,則可能會嘗試群組結尾之後的更多項目)。如果失敗,匹配器會跳到第二個替代方案並嘗試 COND2,而不會回溯到 COND1。如果該方案成功且 BAR 失敗,則會嘗試 COND3。如果 BAZ 隨後失敗,則沒有更多替代方案,因此會回溯到整個群組之前的任何內容。如果 (*THEN) 不在交替中,則其行為類似於 (*PRUNE)。
(*THEN:NAME) 的行為與 (MARK:NAME)(THEN) 不同。它類似於 (*MARK:NAME),因為名稱會被記住,以便傳回給呼叫者。然而,(*SKIP:NAME) 只會搜尋使用 (*MARK) 設定的名稱。
注意
事實上,(*THEN:NAME) 會記住名稱,這對 Erlang 程式設計師來說沒有用處,因為無法檢索名稱。
不包含 | 字元的子模式只是封閉替代方案的一部分;它不是只有一個替代方案的巢狀交替。(*THEN) 的效果會延伸到此類子模式之外的封閉替代方案。考慮以下模式,其中 A、B 等是複雜的模式片段,在此層級不包含任何 | 字元
A (B(*THEN)C) | D
如果 A 和 B 匹配,但 C 中有失敗,則匹配不會回溯到 A;而是移動到下一個替代方案,即 D。但是,如果包含 (*THEN) 的子模式被賦予替代方案,則其行為會有所不同
A (B(*THEN)C | (*FAIL)) | D
(*THEN) 的效果現在被限制在內部子模式中。在 C 中失敗之後,匹配會移動到 (*FAIL),這會導致整個子模式失敗,因為沒有更多替代方案可嘗試。在這種情況下,匹配現在會回溯到 A。
請注意,條件子模式不被視為具有兩個替代方案,因為永遠只會使用一個。也就是說,條件子模式中的 | 字元具有不同的含義。忽略空格,請考慮
^.*? (?(?=a) a | b(*THEN)c )
如果主體是 "ba",則此模式不匹配。由於 .? 是非貪婪的,它最初匹配零個字元。然後條件 (?=a) 失敗,字元 "b" 匹配,但 "c" 不匹配。此時,匹配不會回溯到 .?,這可能是由於 | 字元的存在而預期的。條件子模式是構成整個模式的單一替代方案的一部分,因此匹配失敗。(如果回溯到 .?,允許它匹配 "b",則匹配會成功。)
以上描述的動詞在後續匹配失敗時,提供了四種不同的「強度」控制
- (*THEN) 是最弱的,會在下一個替代方案中繼續匹配。
- (*PRUNE) 緊隨其後,使在當前起始位置的匹配失敗,但允許推進到下一個字元(對於未錨定的模式)。
- (*SKIP) 類似,只是推進可以超過一個字元。
- (*COMMIT) 是最強的,會導致整個匹配失敗。
多個回溯動詞
如果模式中存在多個回溯動詞,則第一個回溯到的動詞會執行動作。例如,考慮以下模式,其中 A、B 等是複雜的模式片段
(A(*COMMIT)B(*THEN)C|ABD)
如果 A 匹配但 B 失敗,則回溯到 (*COMMIT) 會導致整個匹配失敗。但是,如果 A 和 B 匹配,但 C 失敗,則回溯到 (*THEN) 會導致嘗試下一個替代方案 (ABD)。此行為是一致的,但並不總是與 Perl 中的相同。這表示如果兩個或多個回溯動詞連續出現,則最後一個動詞沒有效果。請考慮以下範例
...(*COMMIT)(*PRUNE)...
如果右側存在匹配失敗,則回溯到 (*PRUNE) 會導致其被觸發,並採取其動作。永遠不會回溯到 (*COMMIT)。
重複群組中的回溯動詞
PCRE 在處理重複群組中的回溯動詞時與 Perl 不同。例如,考慮
/(a(*COMMIT)b)+ac/
如果主體是 "abac",Perl 會匹配,但 PCRE 會失敗,因為群組第二次重複中的 (*COMMIT) 會執行動作。
斷言中的回溯動詞
斷言中的 (*FAIL) 具有其正常效果:它會強制立即回溯。
肯定斷言中的 (*ACCEPT) 會導致斷言成功,而無需進行任何進一步處理。在否定斷言中,(*ACCEPT) 會導致斷言失敗,而無需進行任何進一步處理。
如果其他回溯動詞出現在肯定斷言中,則不會被特殊處理。特別是,(*THEN) 會跳到具有交替的最內層封閉群組中的下一個替代方案,無論這是否在斷言內。
但是,否定斷言是不同的,以確保將肯定斷言變更為否定斷言會變更其結果。回溯到 (*COMMIT)、(*SKIP) 或 (*PRUNE) 會導致否定斷言為真,而無需考慮斷言中的任何其他替代分支。回溯到 (*THEN) 會導致它跳到斷言中的下一個封閉替代方案(正常行為),但如果斷言沒有此類替代方案,則 (*THEN) 的行為類似於 (*PRUNE)。
子程式中的回溯動詞
這些行為的發生與是否遞迴呼叫子模式無關。Perl 中子程式的處理在某些情況下有所不同。
- (*FAIL) 在作為子程序的子模式中具有其正常效果:它會強制立即回溯。
- (*ACCEPT) 在作為子程序的子模式中會導致子程序匹配成功,而無需進一步處理。然後,匹配會在子程序呼叫後繼續。
- (COMMIT)、(SKIP) 和 (*PRUNE) 在作為子程序的子模式中會導致子程序匹配失敗。
- (THEN) 會跳至子模式內最內層封閉群組中的下一個替代方案,該群組具有替代方案。如果子模式內沒有此類群組,(THEN) 會導致子程序匹配失敗。
摘要
類型
包含已編譯正規表示式的 Opaque 資料類型。
函數
接受已編譯的正規表示式和項目,並從正規表示式傳回相關資料。
將 Subject
字串的相符部分取代為 Replacement
。
執行正規表示式比對,並傳回 match/{match, Captured}
或 nomatch
。
根據提供的正規表示式尋找 Token,將輸入分割成多個部分。
此函數的傳回值是一個字串,其中包含 Erlang/OTP 編譯中使用的系統的 PCRE 版本。
類型
-type compile_option() :: unicode | anchored | caseless | dollar_endonly | dotall | extended | firstline | multiline | no_auto_capture | dupnames | ungreedy | {newline, nl_spec()} | bsr_anycrlf | bsr_unicode | no_start_optimize | ucp | never_utf.
-type compile_options() :: [compile_option()].
-type mp() :: {re_pattern, _, _, _, _}.
包含已編譯正規表示式的 Opaque 資料類型。
mp/0
保證是一個 tuple(),其第一個元素是 atom re_pattern
,以便在 guard 中進行比對。tuple 的 arity 或其他欄位的內容可能會在未來的 Erlang/OTP 版本中變更。
-type nl_spec() :: cr | crlf | lf | anycrlf | any.
-type option() :: anchored | global | notbol | noteol | notempty | notempty_atstart | report_errors | {offset, non_neg_integer()} | {match_limit, non_neg_integer()} | {match_limit_recursion, non_neg_integer()} | {newline, NLSpec :: nl_spec()} | bsr_anycrlf | bsr_unicode | {capture, ValueSpec :: capture()} | {capture, ValueSpec :: capture(), Type :: index | list | binary} | compile_option().
-type options() :: [option()].
-type replace_fun() :: fun((binary(), [binary()]) -> iodata() | unicode:charlist()).
函數
-spec compile(Regexp) -> {ok, MP} | {error, ErrSpec} when Regexp :: iodata(), MP :: mp(), ErrSpec :: {ErrString :: string(), Position :: non_neg_integer()}.
與 compile(Regexp,[])
相同
-spec compile(Regexp, Options) -> {ok, MP} | {error, ErrSpec} when Regexp :: iodata() | unicode:charlist(), Options :: [Option], Option :: compile_option(), MP :: mp(), ErrSpec :: {ErrString :: string(), Position :: non_neg_integer()}.
將下方描述的語法正規表示式編譯成內部格式,以便稍後作為 run/2
和 run/3
的參數使用。
如果在程式的生命週期中,相同的表達式將用於比對多個主體,則在比對之前編譯正規表示式會很有用。編譯一次並執行多次,遠比每次想要比對時都進行編譯更有效率。
指定選項 unicode
時,正規表示式將指定為有效的 Unicode charlist()
,否則將指定為任何有效的 iodata/0
。
選項
unicode
- 正規表示式指定為 Unicodecharlist()
,而產生的正規表示式程式碼將針對有效的 Unicodecharlist()
主體執行。使用 Unicode 字元時,也請考慮選項ucp
。anchored
- 強制將模式「錨定」,也就是說,它會限制僅在搜尋字串(「主體字串」)的第一個比對點進行比對。此效果也可以透過模式本身中的適當建構達成。caseless
- 模式中的字母會比對大寫和小寫字母。它等同於 Perl 選項/i
,並且可以在模式內透過(?i)
選項設定進行變更。大寫和小寫字母的定義與 ISO 8859-1 字元集中定義的相同。dollar_endonly
- 模式中的錢字元元字元只在主體字串的結尾進行比對。如果沒有此選項,錢字元也會在字串結尾的換行符號之前立即進行比對(而不是在任何其他換行符號之前)。如果指定了選項multiline
,則會忽略此選項。Perl 中沒有對等選項,並且無法在模式內進行設定。dotall
- 模式中的句點會比對所有字元,包括指示換行符號的字元。如果沒有此選項,當目前位置在換行符號時,句點不會進行比對。此選項等同於 Perl 選項/s
,並且可以在模式內透過(?s)
選項設定進行變更。負類別,例如[^a]
,無論此選項的設定為何,都會始終比對換行符號。extended
- 如果設定此選項,則模式中的大多數空白字元都會完全忽略,除非已逸出或位於字元類別內。但是,不允許在引入各種括號子模式的序列(例如(?>
)內,或在數值量詞(例如{1,3}
)內使用空白。但是,允許在項目和後續量詞之間,以及在量詞和指示佔有性的後續 + 之間使用可忽略的空白。空白過去不包含 VT 字元(程式碼 11),因為 Perl 沒有將此字元視為空白。但是,Perl 在版本 5.18 變更,因此 PCRE 在版本 8.34 跟進,VT 現在被視為空白。
這也會導致字元類別外未逸出的 # 和下一個換行符號(含)之間的字元被忽略。這等同於 Perl 的
/x
選項,並且可以在模式內透過(?x)
選項設定進行變更。透過此選項,可以在複雜的模式中包含註解。但是,請注意,這僅適用於資料字元。空白字元永遠不會出現在模式中的特殊字元序列內,例如在引入條件子模式的序列
(?(
內。firstline
- 非錨定的模式必須在主體字串中的第一個換行符號之前或在該位置進行比對,儘管比對的文字可以跨越換行符號。multiline
- 依預設,PCRE 會將主體字串視為由單行字元組成(即使它包含換行符號)。「行首」元字元 (^
) 只在字串的開頭進行比對,而「行尾」元字元 ($
) 只在字串的結尾或在終止換行符號之前進行比對(除非指定了選項dollar_endonly
)。這與 Perl 中的相同。當指定此選項時,「行首」和「行尾」建構會分別在主體字串中的內部換行符號之後或之前立即進行比對,也會在最開頭和結尾進行比對。這等同於 Perl 選項
/m
,並且可以在模式內透過(?m)
選項設定進行變更。如果主體字串中沒有換行符號,或者模式中沒有^
或$
的出現,則設定multiline
沒有效果。no_auto_capture
- 停用模式中編號擷取括號的使用。任何後面沒有?
的左括號的行為都如同後面跟著?:
。具名括號仍可用於擷取(並且它們會以正常方式取得數字)。Perl 中沒有對等選項。dupnames
- 用於識別擷取子模式的名稱不需要是唯一的。當已知只能比對具名子模式的一個執行個體時,這對某些類型的模式可能很有幫助。具名子模式的更多詳細資訊將在下方提供。ungreedy
- 反轉量詞的「貪婪性」,以便它們依預設不貪婪,但如果後面跟著「?」,則會變成貪婪。它與 Perl 不相容。也可以在模式內透過(?U)
選項設定進行設定。{newline, NLSpec}
- 覆寫主體字串中換行符號的預設定義,在 Erlang 中,換行符號是 LF (ASCII 10)。cr
- 換行符號由單一字元cr
(ASCII 13) 指示。lf
- 換行符號由單一字元 LF (ASCII 10) 指示,這是預設值。crlf
- 換行符號由雙字元 CRLF (ASCII 13 後接 ASCII 10) 序列指示。anycrlf
- 將識別上述三個序列中的任何一個。any
- 上述任何換行符號序列,以及 Unicode 序列 VT (垂直定位字元,U+000B)、FF (換頁符號,U+000C)、NEL (下一行,U+0085)、LS (行分隔符號,U+2028) 和 PS (段落分隔符號,U+2029)。
bsr_anycrlf
- 明確指定 \R 僅比對 CR、LF 或 CRLF 序列,而不是 Unicode 特定的換行符號。bsr_unicode
- 明確指定 \R 比對所有 Unicode 換行符號(包括 CRLF 等,這是預設值)。no_start_optimize
- 停用最佳化,若正規表示式中存在「特殊起始模式項目」則可能導致故障。典型的例子是當使用「(COMMIT)ABC」來匹配「DEFABC」時,PCRE 的起始最佳化會跳過主體直到「A」,而永遠不會意識到 (COMMIT) 指令應該使匹配失敗。此選項僅在您使用「起始模式項目」時才有意義,如PCRE 正規表示式詳細資訊章節中所述。ucp
- 指定在解析 \B、\b、\D、\d、\S、\s、\W 和 \w 時使用 Unicode 字元屬性。若無此旗標,則僅使用 ISO Latin-1 屬性。使用 Unicode 屬性會影響效能,但在處理 ISO Latin-1 範圍以外的 Unicode 字元時,在語義上是正確的。never_utf
- 指定禁止使用 (UTF) 和/或 (UTF8) 「起始模式項目」。此旗標不能與unicode
選項合併使用。若要編譯來自外部來源的 ISO Latin-1 模式時,此選項很有用。
接受已編譯的正規表示式和項目,並從正規表示式傳回相關資料。
唯一支援的項目是 namelist
,它會傳回元組 {namelist, [binary()]}
,其中包含正規表示式中所有(唯一)具名子模式的名稱。
例如
1> {ok,MP} = re:compile("(?<A>A)|(?<B>B)|(?<C>C)").
{ok,{re_pattern,3,0,0,
<<69,82,67,80,119,0,0,0,0,0,0,0,1,0,0,0,255,255,255,255,
255,255,...>>}}
2> re:inspect(MP,namelist).
{namelist,[<<"A">>,<<"B">>,<<"C">>]}
3> {ok,MPD} = re:compile("(?<C>A)|(?<B>B)|(?<C>C)",[dupnames]).
{ok,{re_pattern,3,0,0,
<<69,82,67,80,119,0,0,0,0,0,8,0,1,0,0,0,255,255,255,255,
255,255,...>>}}
4> re:inspect(MPD,namelist).
{namelist,[<<"B">>,<<"C">>]}
請注意,在第二個範例中,重複的名稱在傳回的清單中只會出現一次,且無論名稱在正規表示式中的位置如何,清單都會依字母順序排列。如果將 {capture, all_names}
指定為 run/3
的選項,則名稱的順序與擷取的子表達式的順序相同。因此,您可以從 run/3
的結果建立名稱到值的對應,如下所示:
1> {ok,MP} = re:compile("(?<A>A)|(?<B>B)|(?<C>C)").
{ok,{re_pattern,3,0,0,
<<69,82,67,80,119,0,0,0,0,0,0,0,1,0,0,0,255,255,255,255,
255,255,...>>}}
2> {namelist, N} = re:inspect(MP,namelist).
{namelist,[<<"A">>,<<"B">>,<<"C">>]}
3> {match,L} = re:run("AA",MP,[{capture,all_names,binary}]).
{match,[<<"A">>,<<>>,<<>>]}
4> NameMap = lists:zip(N,L).
[{<<"A">>,<<"A">>},{<<"B">>,<<>>},{<<"C">>,<<>>}]
-spec replace(Subject, RE, Replacement) -> iodata() | unicode:charlist() when Subject :: iodata() | unicode:charlist(), RE :: mp() | iodata(), Replacement :: iodata() | unicode:charlist() | replace_fun().
-spec replace(Subject, RE, Replacement, Options) -> iodata() | unicode:charlist() when Subject :: iodata() | unicode:charlist(), RE :: mp() | iodata() | unicode:charlist(), Replacement :: iodata() | unicode:charlist() | replace_fun(), Options :: [Option], Option :: anchored | global | notbol | noteol | notempty | notempty_atstart | {offset, non_neg_integer()} | {newline, NLSpec} | bsr_anycrlf | {match_limit, non_neg_integer()} | {match_limit_recursion, non_neg_integer()} | bsr_unicode | {return, ReturnType} | CompileOpt, ReturnType :: iodata | list | binary, CompileOpt :: compile_option(), NLSpec :: cr | crlf | lf | anycrlf | any.
將 Subject
字串的相符部分取代為 Replacement
。
允許的選項與 run/3
的選項相同,但 capture
選項不被允許。取而代之的是 {return, ReturnType}
。預設的回傳類型是 iodata
,其建構方式旨在最小化複製。 iodata
結果可以直接在許多 I/O 操作中使用。如果需要扁平的 list/0
,請指定 {return, list}
。如果需要二進位檔,請指定 {return, binary}
。
如同函數 run/3
,以 unicode
選項編譯的 mp/0
需要 Subject
為 Unicode charlist()
。如果隱式完成編譯,並且將 unicode
編譯選項指定給此函數,則正規表示式和 Subject
都必須指定為有效的 Unicode charlist()
。
如果替換內容以字串的形式給出,則它可以包含特殊字元 &
,它會在結果中插入整個匹配的表示式,以及特殊序列 \
N(其中 N 是大於 0 的整數)、\g
N 或 \g{
N}
,這會在結果中插入子表示式編號 N。如果正規表示式未產生該編號的子表達式,則不會插入任何內容。
若要在結果中插入 & 或 \,請在其前面加上 \。請注意,Erlang 已經給予字串中的 \ 特殊含義,因此單個 \ 必須寫成 "\\"
,因此雙 \ 必須寫成 "\\\\"
。
範例
1> re:replace("abcd","c","[&]",[{return,list}]).
"ab[c]d"
while
2> re:replace("abcd","c","[\\&]",[{return,list}]).
"ab[&]d"
如果替換內容以函數的形式給出,則將使用整個匹配的表示式作為第一個引數,並使用正規表示式中出現的順序排列的子表示式匹配的清單來呼叫它。回傳的值將插入結果中。
範例
3> re:replace("abcd", ".(.)",
fun(Whole, [<<C>>]) ->
<<$#, Whole/binary, $-, (C - $a + $A), $#>>
end,
[{return, list}]).
"#ab-B#cd"
注意
如果非匹配的可選子表示式是正規表示式中的最後一個子表示式,則它們將不會包含在子表示式匹配的清單中。
範例
正規表示式
"(a)(b)?(c)?"
(「a」,可選擇後接「b」,可選擇後接「c」)將建立以下子表示式清單:
- 套用至字串
"abc"
時的[<<"a">>, <<"b">>, <<"c">>]
- 套用至字串
"acx"
時的[<<"a">>, <<>>, <<"c">>]
- 套用至字串
"abx"
時的[<<"a">>, <<"b">>]
- 套用至字串
"axx"
時的[<<"a">>]
-spec run(Subject, RE) -> {match, Captured} | nomatch when Subject :: iodata() | unicode:charlist(), RE :: mp() | iodata(), Captured :: [CaptureData], CaptureData :: {integer(), integer()}.
與 run(Subject, RE, [])
等效。
-spec run(Subject, RE, Options) -> {match, Captured} | match | nomatch | {error, ErrType} when Subject :: iodata() | unicode:charlist(), RE :: mp() | iodata() | unicode:charlist(), Options :: options(), Captured :: [CaptureData] | [[CaptureData]], CaptureData :: {integer(), integer()} | ListConversionData | binary(), ListConversionData :: string() | {error, string(), binary()} | {incomplete, string(), binary()}, ErrType :: match_limit | match_limit_recursion | {compile, CompileErr}, CompileErr :: {ErrString :: string(), Position :: non_neg_integer()}.
執行正規表示式比對,並傳回 match/{match, Captured}
或 nomatch
。
正規表示式可以指定為 iodata/0
,在這種情況下,它會自動編譯(如透過 compile/2
)並執行,或者指定為預先編譯的 mp/0
,在這種情況下,它會直接針對主體執行。
若牽涉到編譯,則如果發生編譯錯誤,會擲回 badarg
例外狀況。請呼叫 compile/2
以取得有關正規表示式中錯誤位置的資訊。
如果正規表示式先前已編譯,則選項清單只能包含以下選項:
anchored
{capture, ValueSpec}/{capture, ValueSpec, Type}
global
{match_limit, integer() >= 0}
{match_limit_recursion, integer() >= 0}
{newline, NLSpec}
notbol
notempty
notempty_atstart
noteol
{offset, integer() >= 0}
report_errors
否則,函數 compile/2
的所有有效選項也允許使用。同時允許用於編譯和執行匹配的選項,即 anchored
和 {newline, NLSpec}
,如果與未預先編譯的正規表示式一起存在,則會影響編譯和執行。
如果正規表示式先前已使用 unicode
選項編譯,則 Subject
必須以有效的 Unicode charlist()
的形式提供,否則任何 iodata/0
都可以。若牽涉到編譯且指定了 unicode
選項,則 Subject
和正規表示式都必須指定為有效的 Unicode charlists()
。
{capture, ValueSpec}/{capture, ValueSpec, Type}
定義在成功匹配時從函數傳回的內容。capture
元組可以包含值規格,指定要傳回哪些擷取的子字串,以及類型規格,指定如何傳回擷取的子字串(作為索引元組、清單或二進位檔)。這些選項將在下面詳細說明。
如果擷取選項描述不進行子字串擷取({capture, none}
),則函數會在成功匹配時傳回單個原子 match
,否則會傳回元組 {match, ValueList}
。停用擷取可以透過將 none
或空清單指定為 ValueSpec
來完成。
report_errors
選項增加了傳回錯誤元組的可能性。該元組會指示匹配錯誤(match_limit
或 match_limit_recursion
),或編譯錯誤,其中錯誤元組的格式為 {error, {compile, CompileErr}}
。請注意,如果未指定 report_errors
選項,則函數永遠不會傳回錯誤元組,而是將編譯錯誤報告為 badarg
例外狀況,並將因超出匹配限制而失敗的匹配簡單地報告為 nomatch
。
以下選項與執行相關:
anchored
- 將run/3
限制為在第一個匹配位置進行匹配。如果模式是使用anchored
編譯的,或是因其內容而變成錨定的,則它無法在匹配時取消錨定,因此沒有unanchored
選項。global
- 實作全域(重複)搜尋(Perl 中的旗標g
)。每個匹配都會以單獨的list/0
的形式傳回,其中包含特定匹配和任何匹配的子表達式(或依capture
選項指定)。因此,指定此選項時,回傳值的Captured
部分是list/0
的list/0
。當全域選項與匹配空字串的正規表示式互動時,會讓某些使用者感到驚訝。當指定
global
選項時,run/3
會以與 Perl 相同的方式處理空匹配:在任何位置的長度為零的匹配也會使用選項[anchored, notempty_atstart]
重新嘗試。如果該搜尋的結果長度 > 0,則會包含該結果。範例re:run("cat","(|at)",[global]).
執行以下匹配:
在偏移量
0
- 正規表示式(|at)
首先在字串cat
的初始位置進行匹配,產生結果集[{0,0},{0,0}]
(第二個{0,0}
是因為括號標記的子表達式)。由於匹配的長度為 0,因此我們尚未前進到下一個位置。在偏移量
0
,使用[anchored, notempty_atstart]
- 在相同的位置,使用選項[anchored, notempty_atstart]
重新嘗試搜尋,這不會產生任何更長長度的有趣結果,因此搜尋位置會前進到下一個字元 (a
)。在偏移量
1
- 搜尋結果為[{1,0},{1,0}]
,因此也會使用額外的選項重複此搜尋。在偏移量
1
且[anchored, notempty_atstart]
的情況下 - 找到替代選項ab
,結果為 [{1,2},{1,2}]。此結果會被加入結果列表中,並且在搜尋字串中的位置會向前移動兩步。在偏移量
3
的情況下 - 搜尋再次匹配到空字串,產生[{3,0},{3,0}]
。在偏移量
1
且[anchored, notempty_atstart]
的情況下 - 這個情況沒有產生長度 > 0 的結果,而且我們已到達最後位置,因此全域搜尋完成。
此呼叫的結果為
{match,[[{0,0},{0,0}],[{1,0},{1,0}],[{1,2},{1,2}],[{3,0},{3,0}]]}
notempty
- 如果指定此選項,則空字串不會被視為有效的匹配項。如果模式中存在替代選項,則會嘗試這些選項。如果所有替代選項都匹配到空字串,則整個匹配將會失敗。範例
如果將以下模式應用於一個不是以 "a" 或 "b" 開頭的字串,通常會匹配到主體開頭的空字串
a?b?
使用選項
notempty
,此匹配無效,因此run/3
會進一步在字串中搜尋 "a" 或 "b" 的出現。notempty_atstart
- 類似於notempty
,只是允許在主體開頭之外匹配到空字串。如果模式已錨定,則只有在模式包含 \K 時才會發生此類匹配。Perl 沒有與
notempty
或notempty_atstart
直接對應的選項,但它在 split() 函式中以及使用修飾符/g
時,確實會對空字串的模式匹配進行特殊處理。在匹配到空字串後,可以通過先使用notempty_atstart
和anchored
在相同偏移量再次嘗試匹配,如果失敗,則前進起始偏移量(請參閱下文)並再次嘗試一般匹配,來模擬 Perl 的行為。notbol
- 指定主體字串的第一個字符不是行的開頭,因此脫字符號不會在其之前進行匹配。在未設定multiline
(在編譯時) 的情況下設定此項,將會導致脫字符號永遠不會匹配。此選項僅影響脫字符號的行為。它不會影響 \A。noteol
- 指定主體字串的結尾不是行的結尾,因此美元符號不會匹配它,也不會匹配緊接在其之前的新行 (多行模式除外)。在未設定multiline
(在編譯時) 的情況下設定此項,將會導致美元符號永遠不會匹配。此選項僅影響美元符號的行為。它不會影響 \Z 或 \z。report_errors
- 更好地控制run/3
中的錯誤處理。指定後,編譯錯誤(如果正規表示式尚未編譯)和執行階段錯誤會明確地以錯誤元組的形式返回。以下是可能的執行階段錯誤
match_limit
- PCRE 函式庫會對內部匹配函式的呼叫次數設定限制。在為 Erlang 編譯的函式庫中,預設值為 10,000,000。如果返回{error, match_limit}
,則表示正規表示式的執行已達到此限制。通常會將其視為nomatch
,這是發生這種情況時的預設傳回值,但通過指定report_errors
,您可以在匹配因內部呼叫次數過多而失敗時收到通知。match_limit_recursion
- 此錯誤與match_limit
非常相似,但發生在 PCRE 的內部匹配函式被「遞迴」呼叫的次數超過match_limit_recursion
限制時,該限制的預設值也是 10,000,000。請注意,只要將match_limit
和match_limit_default
的值保持在預設值,就不會發生match_limit_recursion
錯誤,因為match_limit
錯誤會先發生(每次遞迴呼叫也是一次呼叫,但反之則不然)。但是,可以通過直接在正規表示式字串中設定限制(請參閱「PCRE 正規表示式詳細資訊」一節),或通過為run/3
指定選項來更改這兩個限制。
重要的是要理解,在限制匹配時所指的「遞迴」並不是 Erlang 機器的 C 堆疊或 Erlang 程序堆疊上的遞迴。編譯到 Erlang VM 中的 PCRE 版本使用機器「堆」記憶體來儲存在正規表示式匹配中的遞迴期間必須保留的值。
{match_limit, integer() >= 0}
- 以實作特定的方式限制匹配的執行時間。PCRE 文件將其描述如下match_limit 欄位提供了一種方法,可防止 PCRE 在執行不會匹配,但搜尋樹中存在大量可能性的模式時耗用大量資源。經典範例是使用巢狀無限制重複的模式。
在內部,pcre_exec() 使用名為 match() 的函式,它會重複 (有時是遞迴地) 呼叫該函式。match_limit 設定的限制是對在匹配期間呼叫此函式的次數設定限制,這會產生限制可能發生的回溯次數的效果。對於未錨定的模式,主體字串中每個位置的計數都從零開始。
這表示,如果使用此選項降低限制,失控的正規表示式匹配可以更快地失敗。預設值 10,000,000 已編譯到 Erlang VM 中。
注意
此選項不會以任何方式影響 Erlang VM 在「長時間執行的 BIF」方面的執行。
run/3
總是會在確保 Erlang 系統的即時特性的間隔時間將控制權交還給 Erlang 程序的排程器。{match_limit_recursion, integer() >= 0}
- 以實作特定的方式限制匹配的執行時間和記憶體消耗,與match_limit
非常相似。PCRE 文件將其描述如下match_limit_recursion 欄位與 match_limit 類似,但它不是限制呼叫 match() 的總次數,而是限制遞迴深度。遞迴深度小於呼叫總次數,因為並非所有對 match() 的呼叫都是遞迴的。此限制僅在設定為小於 match_limit 時才有用。
限制遞迴深度會限制可使用的機器堆疊量,或者,當 PCRE 編譯為在堆上而不是堆疊上使用記憶體時,會限制可使用的堆記憶體量。
當發生正規表示式匹配遞迴時,Erlang VM 使用 PCRE 函式庫,其中使用堆記憶體。因此,這會限制機器堆的使用,而不是 C 堆疊。
指定較小的值可能會導致具有深度遞迴的匹配失敗,即使它們應該匹配
1> re:run("aaaaaaaaaaaaaz","(a+)*z"). {match,[{0,14},{0,13}]} 2> re:run("aaaaaaaaaaaaaz","(a+)*z",[{match_limit_recursion,5}]). nomatch 3> re:run("aaaaaaaaaaaaaz","(a+)*z",[{match_limit_recursion,5},report_errors]). {error,match_limit_recursion}
只有在極少數情況下才應使用此選項和選項
match_limit
。建議在竄改這些限制之前,先了解 PCRE 函式庫的內部結構。{offset, integer() >= 0}
- 從主體字串中指定的偏移量 (位置) 開始匹配。偏移量是從零開始的,因此預設值為{offset,0}
(主體字串的所有內容)。{newline, NLSpec}
- 覆寫主體字串中換行符號的預設定義,在 Erlang 中,換行符號是 LF (ASCII 10)。cr
- 換行符號由單個字符 CR (ASCII 13) 表示。lf
- 換行符號由單一字元 LF (ASCII 10) 指示,這是預設值。crlf
- 換行符號由雙字元 CRLF (ASCII 13 後接 ASCII 10) 序列指示。anycrlf
- 會識別上述三個序列中的任何一個。any
- 上述任何換行符號序列,以及 Unicode 序列 VT (垂直定位字元,U+000B)、FF (換頁符號,U+000C)、NEL (下一行,U+0085)、LS (行分隔符號,U+2028) 和 PS (段落分隔符號,U+2029)。
bsr_anycrlf
- 特別指定 \R 僅匹配 CR LF 或 CRLF 序列,而不匹配 Unicode 特有的換行符號。(覆蓋編譯選項。)bsr_unicode
- 特別指定 \R 匹配所有 Unicode 換行符號 (包括 CRLF 等,預設值)。(覆蓋編譯選項。){capture, ValueSpec}
/{capture, ValueSpec, Type}
- 指定要傳回哪些捕獲的子字串以及以何種格式傳回。預設情況下,run/3
會捕獲子字串的所有匹配部分和所有捕獲子模式(會自動捕獲整個模式)。預設的傳回類型是字串捕獲部分的 (從零開始的) 索引,指定為{Offset,Length}
對 (捕獲的index
Type
)。作為預設行為的範例,以下呼叫會傳回作為第一個且唯一捕獲的字串,主體 ("abcd" 在中間) 的匹配部分作為索引對
{3,4}
,其中字符位置是從零開始的,就像偏移量一樣re:run("ABCabcdABC","abcd",[]).
此呼叫的傳回值為
{match,[{3,4}]}
另一個 (相當常見) 的情況是,正規表示式匹配主體的所有內容
re:run("ABCabcdABC",".*abcd.*",[]).
這裡的傳回值對應地指出所有字串,從索引 0 開始,長度為 10 個字符
{match,[{0,10}]}
如果正規表示式包含捕獲子模式,例如
re:run("ABCabcdABC",".*(abcd).*",[]).
則會捕獲所有匹配的主體,以及捕獲的子字串
{match,[{0,10},{3,4}]}
完整匹配模式始終在清單中提供第一個傳回值,其餘子模式則按照其在正規表示式中出現的順序加入。
捕獲元組的建立方式如下
ValueSpec
- 指定要傳回哪些捕獲的 (子) 模式。ValueSpec
可以是描述預定義傳回值集的原子,也可以是包含要傳回的特定子模式的索引或名稱的清單。以下是子模式的預定義集合
all
- 所有捕獲的子模式,包括完整匹配的字串。這是預設值。all_names
- 正規表示式中所有命名的子模式,就像指定了所有名稱的list/0
(依字母順序排列)。所有名稱的清單也可以使用inspect/2
檢索。first
- 僅第一個捕獲的子模式,它始終是主體的完整匹配部分。所有明確捕獲的子模式都會被捨棄。all_but_first
- 除第一個匹配的子模式之外的所有子模式,也就是所有明確捕獲的子模式,但不包括主體字串的完整匹配部分。如果正規表示式整體上匹配主體的大部分,但您感興趣的部分位於明確捕獲的子模式中,則此選項很有用。如果傳回類型為list
或binary
,則不傳回您不感興趣的子模式是優化效能的好方法。none
- 不傳回匹配的子模式,當成功匹配時,會傳回單個原子match
作為函式的傳回值,而不是{match, list()}
傳回值。指定空清單會產生相同的行為。
值清單是要傳回的子模式的索引清單,其中索引 0 代表整個模式,而 1 代表正規表示式中的第一個明確捕獲子模式,依此類推。在正規表示式中使用命名捕獲子模式 (請參閱下文) 時,可以使用
atom/0
或string/0
來指定要傳回的子模式。例如,考慮正規表示式".*(abcd).*"
比對字串 "ABCabcdABC",只擷取 "abcd" 部分(第一個明確的子模式)
re:run("ABCabcdABC",".*(abcd).*",[{capture,[1]}]).
此呼叫會產生以下結果,因為第一個明確擷取的子模式是 "(abcd)",在主體中比對到 "abcd",位置(從零開始)為 3,長度為 4
{match,[{3,4}]}
考慮相同的正規表示式,但子模式明確命名為 'FOO'
".*(?<FOO>abcd).*"
使用此表達式,我們仍然可以使用以下呼叫給出子模式的索引
re:run("ABCabcdABC",".*(?<FOO>abcd).*",[{capture,[1]}]).
得到與之前相同的結果。但是,由於子模式已命名,我們也可以在值清單中指定其名稱
re:run("ABCabcdABC",".*(?<FOO>abcd).*",[{capture,['FOO']}]).
這會產生與先前範例相同的結果,即
{match,[{3,4}]}
值清單可以指定正規表示式中不存在的索引或名稱,在這種情況下,傳回值會根據類型而有所不同。如果類型為
index
,則對於正規表示式中沒有對應子模式的值,會傳回元組{-1,0}
,但對於其他類型(binary
和list
),則值分別為空的二進制或清單。Type
- (可選)指定如何傳回擷取的子字串。如果省略,則會使用預設值index
。Type
可以是以下之一index
- 傳回擷取的子字串,其形式為主體字串中的位元組索引配對以及主體中比對字串的長度(如同在比對前使用erlang:iolist_to_binary/1
或unicode:characters_to_binary/2
將主體字串攤平)。請注意,選項unicode
會產生 (可能虛擬) UTF-8 編碼 二進制中的位元組導向索引。因此,當unicode
生效時,位元組索引元組{0,2}
可以表示一個或兩個字元。這可能看起來違反直覺,但已被認為是最有效且有用的方法。如果需要,傳回清單可以簡化程式碼。此傳回類型為預設值。list
- 將比對到的子字串傳回為字元清單(Erlangstring/0
)。如果在正規表示式中將選項unicode
與 \C 序列結合使用,則擷取的子模式可能包含不是有效的 UTF-8 位元組(\C 比對位元組,不論字元編碼為何)。在這種情況下,list
擷取可能會產生與unicode:characters_to_list/2
可能傳回的相同類型的元組,即帶有標籤incomplete
或error
的三元組,成功轉換的字元以及轉換的無效 UTF-8 尾部(以二進制形式)。最好的策略是在擷取清單時避免使用 \C 序列。binary
- 將比對到的子字串傳回為二進制。如果使用選項unicode
,這些二進制將為 UTF-8。如果 \C 序列與unicode
一起使用,則二進制可能不是有效的 UTF-8。
一般來說,當
type
為index
時,在比對中未指定值的子模式會以元組{-1,0}
傳回。對於其他傳回類型,未指定的子模式會分別傳回為空的二進制或清單。考慮以下正規表示式".*((?<FOO>abdd)|a(..d)).*"
有三個明確擷取的子模式,其中開頭括號的位置決定了結果中的順序,因此
((?<FOO>abdd)|a(..d))
是子模式索引 1,(?<FOO>abdd)
是子模式索引 2,(..d)
是子模式索引 3。當比對以下字串時"ABCabcdABC"
索引 2 的子模式不比對,因為字串中不存在 "abdd",但完整的模式比對(因為有替代的
a(..d)
)。因此,索引 2 的子模式未指定,預設的傳回值為{match,[{0,10},{3,4},{-1,0},{4,3}]}
將擷取
Type
設定為binary
會產生{match,[<<"ABCabcdABC">>,<<"abcd">>,<<>>,<<"bcd">>]}
此處,空的二進制 (
<<>>
) 表示未指定的子模式。在binary
的情況下,會遺失有關比對的一些資訊,因為<<>>
也可能是一個擷取的空字串。如果需要區分空的比對和不存在的子模式,請使用
type
index
,並在 Erlang 程式碼中轉換為最終類型。當指定選項
global
時,capture
規格會分別影響每個比對,因此re:run("cacb","c(a|b)",[global,{capture,[1],list}]).
會產生
{match,[["a"],["b"]]}
有關僅影響編譯步驟的選項說明,請參閱 compile/2
。
-spec split(Subject, RE) -> SplitList when Subject :: iodata() | unicode:charlist(), RE :: mp() | iodata(), SplitList :: [iodata() | unicode:charlist()].
與 split(Subject, RE, [])
等效。
-spec split(Subject, RE, Options) -> SplitList when Subject :: iodata() | unicode:charlist(), RE :: mp() | iodata() | unicode:charlist(), Options :: [Option], Option :: anchored | notbol | noteol | notempty | notempty_atstart | {offset, non_neg_integer()} | {newline, nl_spec()} | {match_limit, non_neg_integer()} | {match_limit_recursion, non_neg_integer()} | bsr_anycrlf | bsr_unicode | {return, ReturnType} | {parts, NumParts} | group | trim | CompileOpt, NumParts :: non_neg_integer() | infinity, ReturnType :: iodata | list | binary, CompileOpt :: compile_option(), SplitList :: [RetData] | [GroupedRetData], GroupedRetData :: [RetData], RetData :: iodata() | unicode:charlist() | binary() | list().
根據提供的正規表示式尋找 Token,將輸入分割成多個部分。
分割基本上是透過執行全域正規表示式比對,並在每次發生比對時分割初始字串來完成的。字串中比對的部分會從輸出中移除。
如同在 run/3
中一樣,使用選項 unicode
編譯的 mp/0
需要 Subject
為 Unicode charlist()
。如果編譯是隱含完成的,且在此函數中指定 unicode
編譯選項,則正規表示式和 Subject
都必須指定為有效的 Unicode charlist()
。
結果以「字串」清單的形式提供,其為選項 return
中指定的慣用資料類型(預設為 iodata
)。
如果正規表示式中指定了子表達式,則比對到的子表達式也會在結果清單中傳回。例如
re:split("Erlang","[ln]",[{return,list}]).
會產生
["Er","a","g"]
while
re:split("Erlang","([ln])",[{return,list}]).
會產生
["Er","l","a","n","g"]
比對子表達式(在正規表示式中以括號標記)的文字會插入到結果清單中其所在的位置。這表示當整個正規表示式為單一子表達式時(如最後一個範例),串連分割的結果總是會產生原始字串。
由於在範例的最後一部分("g")中沒有比對的子表達式,因此之後不會插入任何內容。若要使字串群組和比對子表達式的部分更清楚,可以使用選項 group
,這會在字串分割時將主體字串的部分與比對子表達式的部分分組在一起
re:split("Erlang","([ln])",[{return,list},group]).
會產生
[["Er","l"],["a","n"],["g"]]
這裡的正規表示式首先比對 "l",導致 "Er" 成為結果的第一部分。當正規表示式比對時,(唯一的)子表達式繫結到 "l",因此 "l" 與 "Er" 一起插入到群組中。下一個比對是 "n",使 "a" 成為下一個要傳回的部分。由於在此情況下,子表達式繫結到子字串 "n",因此 "n" 會插入到此群組中。最後一個群組由剩餘的字串組成,因為找不到更多比對。
依預設,函數會傳回字串的所有部分,包括空字串,例如
re:split("Erlang","[lg]",[{return,list}]).
會產生
["Er","an",[]]
由於比對字串結尾的 "g" 會留下空的剩餘部分,因此也會傳回。此行為與 Perl 中 split 函數的預設行為不同,後者預設會移除結尾的空字串。若要取得 Perl 的「修剪」預設行為,請指定 trim
作為選項
re:split("Erlang","[lg]",[{return,list},trim]).
會產生
["Er","an"]
"trim" 選項表示:「給我盡可能多的部分,但不包括空的部分」,這有時會很有用。您也可以透過指定 {parts,
N}
來指定想要多少部分
re:split("Erlang","[lg]",[{return,list},{parts,2}]).
會產生
["Er","ang"]
請注意,最後一部分是 "ang",而不是 "an",因為分割指定為兩個部分,且當提供足夠的部分時分割就會停止,這就是結果與 trim
的結果不同的原因。
使用此輸入資料無法產生三個以上的部分,因此
re:split("Erlang","[lg]",[{return,list},{parts,4}]).
會產生與預設值相同的結果,這可以視為「無限個部分」。
將部分數指定為 0
會產生與選項 trim
相同的效果。如果擷取了子表達式,則在指定 trim
或 {parts,0}
時,從結果中也會移除結尾比對到的空子表達式。
trim
行為與 Perl 的預設值完全對應。{parts,N}
(其中 N 是正整數)與 Perl 行為及其正數數值第三個參數完全對應。split/3
的預設行為與 Perl 常式指定負整數作為第三個參數時的 Perl 行為對應。
未在函數 run/3
中說明之選項的摘要
{return,ReturnType}
- 指定結果清單中如何呈現原始字串的部分。有效類型iodata
-iodata/0
的變體,在使用目前的實作時,資料複製量最少(通常為二進制,但不要依賴它)。binary
- 所有部分都以二進制形式傳回。list
- 所有部分都以字元清單(「字串」)形式傳回。
group
- 將字串的部分與正規表示式之子表達式中比對到的字串部分分組在一起。在此情況下,函數的傳回值為
list/0
的list/0
。每個子清單的開頭為主體字串中選取的字串,後面接著比對正規表示式中每個子表達式的部分(依其出現順序)。{parts,N}
- 指定主體字串要分割成多少個部分。部分數必須是正整數,才能表示特定最大部分數,而
infinity
則表示可能的最大部分數(預設值)。指定{parts,0}
會產生盡可能多的部分,但不考慮結尾的空部分,這與指定trim
相同。trim
- 指定要忽略結果清單結尾的空部分。與指定{parts,0}
相同。這與 Perl 中split
內建函數的預設行為對應。
-spec version() -> binary().
此函數的傳回值是一個字串,其中包含 Erlang/OTP 編譯中使用的系統的 PCRE 版本。