內容

名稱

perlrecharclass - Perl 正規表示式字元類別

說明

關於 Perl 正規表示式的頂層文件可以在 perlre 中找到。

此手冊頁討論 Perl 正規表示式中字元類別的語法和用法。

字元類別是一種表示字元集的方式,以匹配該集中的某個字元。請務必記住:匹配字元類別會消耗來源字串中的正好一個字元。(來源字串是正規表示式與之匹配的字串。)

Perl 正規表示式中有三種類型的字元類別:點號、反斜線序列和方括號括起來的形式。不過請記住,「字元類別」一詞通常用於表示方括號形式。當然,大多數 Perl 文件都是這樣做的。

點號

點號(或句點),. 可能是最常用的,當然也是最著名的字元類別。預設情況下,點號匹配任何字元,除了換行符號。可以使用單行修飾符來變更該預設值,以加入匹配換行符號:對於整個正規表示式,使用 /s 修飾符,或使用 (?s) 在區域中使用(甚至可以在 use re '/s' 的範圍內全局使用)。(下面描述的反斜線序列 "\N" 匹配除換行符號之外的任何字元,而不考慮單行修飾符。)

以下是幾個範例

"a"  =~  /./       # Match
"."  =~  /./       # Match
""   =~  /./       # No match (dot has to match a character)
"\n" =~  /./       # No match (dot does not match a newline)
"\n" =~  /./s      # Match (global 'single line' modifier)
"\n" =~  /(?s:.)/  # Match (local 'single line' modifier)
"ab" =~  /^.$/     # No match (dot matches one character)

反斜線序列

反斜線序列是一系列字元,第一個字元是反斜線。Perl 將特殊意義歸因於許多這樣的序列,其中一些是字元類別。也就是說,它們各匹配一個單一字元,前提是該字元屬於序列定義的特定字元集。

以下是字元類別的反斜線序列清單。它們在下面有更詳細的討論。(對於不是字元類別的反斜線序列,請參閱 perlrebackslash。)

\d             Match a decimal digit character.
\D             Match a non-decimal-digit character.
\w             Match a "word" character.
\W             Match a non-"word" character.
\s             Match a whitespace character.
\S             Match a non-whitespace character.
\h             Match a horizontal whitespace character.
\H             Match a character that isn't horizontal whitespace.
\v             Match a vertical whitespace character.
\V             Match a character that isn't vertical whitespace.
\N             Match a character that isn't a newline.
\pP, \p{Prop}  Match a character that has the given Unicode property.
\PP, \P{Prop}  Match a character that doesn't have the Unicode property

\N

\N,從 v5.12 開始提供,與點號一樣,匹配任何不是換行符號的字元。不同之處在於 \N 不受單行正規表示式修飾符的影響(請參閱上面的 "點號")。請注意,\N{...} 形式可能表示完全不同的東西。當 {...}量詞 時,表示匹配非換行字元這麼多次。例如,\N{3} 表示匹配 3 個非換行字元;\N{5,} 表示匹配 5 個或更多非換行字元。但是,如果 {...} 不是合法的量詞,則假設它是一個命名字元。請參閱 charnames 了解這些字元。例如,\N{COLON}\N{4F}\N{F4} 都沒有包含合法的量詞,因此 Perl 會嘗試尋找名稱分別為 COLON4FF4 的字元。

數字

\d 符合被視為十進制數字的單一字元。如果 /a 正規表示式修飾詞生效,它符合 [0-9]。否則,它符合 \p{Digit} 所符合的任何內容,其中包含 [0-9]。(一個不太可能的例外是,在區域設定比對規則下,目前的區域設定可能不會有 [0-9] 符合 \d,和/或可能符合其他碼點小於 256 的字元。唯一合法的此類區域設定定義會是符合 [0-9] 加上另一組 10 個連續數字字元;任何其他內容都會違反 C 語言標準,但 Perl 目前不會對此假設任何內容。)

這表示,除非 /a 修飾詞生效,否則 \d 不僅符合數字 '0' - '9',也符合阿拉伯數字、天城文數字,以及其他語言的數字。這可能會造成一些混淆,以及一些安全性問題。

\d 符合的一些數字看起來像某些 [0-9],但有不同的值。例如,孟加拉數字四 (U+09EA) 看起來很像 ASCII 數字八 (U+0038),而雷布查數字六 (U+1C46) 看起來很像 ASCII 數字五 (U+0035)。一個只預期 ASCII 數字的應用程式可能會被誤導,或者如果比對是 \d+,符合的字串可能會包含來自不同書寫系統的數字混合,看起來它們表示的數字與實際不同的數字。Unicode::UCD 中的 "num()" 可用於安全地計算值,如果輸入字串包含此類混合,則傳回 undef。否則,例如,顯示的價格可能會故意與其顯示方式不同。

\p{Digit} 的意思(因此 \d 除非在 /a 修飾詞下)是 \p{General_Category=Decimal_Number},或同義的 \p{General_Category=Digit}。從 Unicode 版本 4.1 開始,這是與 \p{Numeric_Type=Decimal} 符合的相同字元組。但 Unicode 也有另一個具有類似名稱的屬性,\p{Numeric_Type=Digit},它符合完全不同的字元組。這些字元是例如 圈起來的數字一 或下標,或來自缺少所有十個數字的書寫系統。

設計意圖是讓 \d 精確符合可安全地用於「正常」大端位置十進制語法的字元組,其中,例如 123 表示一個「百」,加上兩個「十」,加上三個「一」。此位置表示法不一定適用於符合另一種類型「數字」\p{Numeric_Type=Digit} 的字元,因此 \d 沒有符合它們。

泰米爾數字(U+0BE6 - U+0BEF)也可以合法地用於舊式泰米爾數字中,其中它們最多只能連續出現一次,並由表示「乘以 10」、「乘以 100」等含意的字元分隔。(請參閱 https://www.unicode.org/notes/tn21。)

任何與 \d 不匹配的字元都與 \D 匹配。

字元

\w 匹配單一字母數字字元(字母字元或十進制數字);或連接標點字元,例如底線(「_」);或「標記」字元(例如某種重音符號),其附加到這些字元之一。它不匹配整個字詞。若要匹配整個字詞,請使用 \w+。這與匹配英文單字不同,但在 ASCII 範圍內,它與 Perl 識別字元字串相同。

如果 /a 修飾詞生效 ...

\w 匹配 63 個字元 [a-zA-Z0-9_]。

否則 ...
對於 255 以上的碼點 ...

\w 匹配與 \p{Word} 在此範圍內匹配的相同內容。亦即,它匹配泰文字母、希臘字母等。這包括連接標點(例如底線),其連接兩個字詞,或變音符號,例如 組合波浪號 和修飾字母,通常用於為字母新增輔助標記。

對於 256 以下的碼點 ...
如果地區設定規則生效 ...

\w 匹配平台的原生底線字元,加上地區設定視為字母數字的任何內容。

如果相反地,Unicode 規則生效 ...

\w 匹配與 \p{Word} 匹配的完全相同內容。

否則 ...

\w 匹配 [a-zA-Z0-9_]。

套用哪些規則的判定方式如 perlre 中的「哪個字元集修飾詞生效?」 所述。

Unicode 字元清單中包含許多安全性問題。請參閱 http://unicode.org/reports/tr36

此外,對於程式語言識別碼中超出 ASCII 範圍的字元組,您可能希望改用更自訂的 "Unicode 屬性"\p{ID_Start}\p{ID_Continue}\p{XID_Start}\p{XID_Continue}。請參閱 http://unicode.org/reports/tr31

\w 無法比對的任何字元都可以由 \W 比對。

空白

\s 比對任何被視為空白的單一字元。

如果 /a 修改器有效 ...

在所有 Perl 版本中,\s 比對 5 個字元 [\t\n\f\r];也就是水平標籤、換行符號、換頁符號、回車符號和空白。從 Perl v5.18 開始,它也比對垂直標籤 \cK。請參閱下方的註解 [1] 以了解相關討論。

否則 ...
對於超過 255 的碼點 ...

\s 精確比對下表中「s」欄位顯示的超過 255 的碼點。

對於低於 256 的碼點 ...
如果地區規則有效 ...

\s 比對地區規則視為空白的任何內容。

如果 Unicode 規則有效 ...

\s 精確比對下表中「s」欄位顯示的字元。

否則 ...

\s 比對 [\t\n\f\r],從 Perl v5.18 開始,也比對垂直標籤 \cK。(請參閱下方的註解 [1] 以了解相關討論。)請注意,此清單不包含不換行空白。

套用哪些規則的判定方式如 perlre 中的「哪個字元集修飾詞生效?」 所述。

任何未與 \s 匹配的字元都與 \S 匹配。

\h 匹配任何被視為水平空白字元的字元;這包括平台的空白和 tab 字元,以及下方表格中列出的其他幾個字元。\H 匹配任何未被視為水平空白字元的字元。它們使用平台的原生字元集,並且不考慮可能正在使用的任何區域設定。

\v 匹配任何被視為垂直空白字元的字元;這包括平台的回車和換行字元(新行),以及下方表格中列出的其他幾個字元。\V 匹配任何未被視為垂直空白字元的字元。它們使用平台的原生字元集,並且不考慮可能正在使用的任何區域設定。

\R 匹配任何在 Unicode 規則下可被視為新行的內容。它可以匹配多字元序列。它不能用於方括號字元類別中;請改用 \v(垂直空白)。它使用平台的原生字元集,並且不考慮可能正在使用的任何區域設定。詳細資訊會在 perlrebackslash 中討論。

請注意,與 \s(以及 \d\w)不同,\h\v 始終匹配相同的字元,而不考慮其他因素,例如作用中的區域設定或原始字串是否為 UTF-8 格式。

人們可能會認為 \s 等於 [\h\v]。從 Perl v5.18 開始確實如此,但在那之前,唯一的不同是垂直 tab("\cK")未與 \s 匹配。

以下表格是截至 Unicode 14.0 為止,由 \s\h\v 匹配的字元的完整清單。

第一欄提供字元的 Unicode 碼點(十六進位格式),第二欄提供(Unicode)名稱。第三欄表示字元與哪些類別匹配(假設沒有任何區域設定會變更 \s 匹配)。

0x0009        CHARACTER TABULATION   h s
0x000a              LINE FEED (LF)    vs
0x000b             LINE TABULATION    vs  [1]
0x000c              FORM FEED (FF)    vs
0x000d        CARRIAGE RETURN (CR)    vs
0x0020                       SPACE   h s
0x0085             NEXT LINE (NEL)    vs  [2]
0x00a0              NO-BREAK SPACE   h s  [2]
0x1680            OGHAM SPACE MARK   h s
0x2000                     EN QUAD   h s
0x2001                     EM QUAD   h s
0x2002                    EN SPACE   h s
0x2003                    EM SPACE   h s
0x2004          THREE-PER-EM SPACE   h s
0x2005           FOUR-PER-EM SPACE   h s
0x2006            SIX-PER-EM SPACE   h s
0x2007                FIGURE SPACE   h s
0x2008           PUNCTUATION SPACE   h s
0x2009                  THIN SPACE   h s
0x200a                  HAIR SPACE   h s
0x2028              LINE SEPARATOR    vs
0x2029         PARAGRAPH SEPARATOR    vs
0x202f       NARROW NO-BREAK SPACE   h s
0x205f   MEDIUM MATHEMATICAL SPACE   h s
0x3000           IDEOGRAPHIC SPACE   h s
[1]

在 Perl v5.18 之前,\s 沒有匹配垂直 tab。[^\S\cK](模糊地)匹配 \s 傳統上所做的。

[2]

換行和不換行空白可能會或可能不會與 \s 匹配,具體取決於生效的規則。請參閱 本節開頭

Unicode 屬性

\pP\p{Prop} 是用於比對符合給定 Unicode 屬性的字元的字元類別。單一字母屬性名稱可以使用 \pP 形式,屬性名稱置於 \p 之後,否則需要大括號。使用大括號時,有一個單一形式,即只將屬性名稱置於大括號中,以及一個複合形式,看起來像 \p{name=value},表示當字元的「名稱」屬性具有特定「值」時比對。例如,可以將數字的比對寫成 /\pN//\p{Number}/,或 /\p{Number=True}/。小寫字母會比對到屬性 Lowercase_Letter,其簡寫形式為 Ll。它們需要大括號,因此寫成 /\p{Ll}//\p{Lowercase_Letter}/,或 /\p{General_Category=Lowercase_Letter}/(底線為選用)。/\pLl/ 有效,但表示不同的東西。它比對一個兩個字元的字串:一個字母(Unicode 屬性 \pL),後接一個小寫 l

Unicode 屬性比對的內容從不受地區設定規則約束,而且如果地區設定規則未以其他方式生效,使用 Unicode 屬性會強制正規表示式使用 Unicode 規則(如果尚未使用)。

請注意,幾乎所有屬性都不受大小寫不敏感比對影響。也就是說,加入 /i 正規表示式修飾符不會改變它們比對的內容。但有兩組會受到影響。第一組是 Uppercase_LetterLowercase_LetterTitlecase_Letter,所有這些在 /i 比對下都會比對到 Cased_Letter。第二組是 UppercaseLowercaseTitlecase,所有這些在 /i 比對下都會比對到 Cased。(這些組之間的差異在於有些東西,例如羅馬數字,有大小寫,因此它們是 Cased,但不被視為字母,因此它們不是 Cased_Letter。它們實際上是 Letter_Number。)此組也包含其子集 PosixUpperPosixLower,在 /i 下兩者都會比對到 PosixAlpha

有關 Unicode 屬性的更多詳細資訊,請參閱 perlunicode 中的「Unicode 字元屬性」;有關可能屬性的完整清單,請參閱 perluniprops 中的「可透過 \p{} 和 \P{} 存取的屬性」,其中註明所有具有 /i 差異的形式。也可以定義自己的屬性。這在 perlunicode 中的「使用者定義的字元屬性」 中有說明。

Unicode 屬性定義(驚喜!)僅在 Unicode 碼點上。從 v5.20 開始,在與 \p\P 匹配時,Perl 將非 Unicode 碼點(那些超過 0x10FFFF 的合法 Unicode 最大值)視為典型的未指派 Unicode 碼點。

在 v5.20 之前,Perl 會針對非 Unicode 碼點提出警告,並讓所有匹配失敗。這可能會有點令人驚訝

chr(0x110000) =~ \p{ASCII_Hex_Digit=True}     # Fails on Perls < v5.20.
chr(0x110000) =~ \p{ASCII_Hex_Digit=False}    # Also fails on Perls
                                              # < v5.20

儘管這兩個匹配可能被視為互補,但直到 v5.20,它們僅在 Unicode 碼點上才如此。

從 perl v5.30 開始,Unicode 屬性值中允許使用萬用字元。請參閱 "perlunicode 中的「屬性值中的萬用字元」

範例

"a"  =~  /\w/      # Match, "a" is a 'word' character.
"7"  =~  /\w/      # Match, "7" is a 'word' character as well.
"a"  =~  /\d/      # No match, "a" isn't a digit.
"7"  =~  /\d/      # Match, "7" is a digit.
" "  =~  /\s/      # Match, a space is whitespace.
"a"  =~  /\D/      # Match, "a" is a non-digit.
"7"  =~  /\D/      # No match, "7" is not a non-digit.
" "  =~  /\S/      # No match, a space is not non-whitespace.

" "  =~  /\h/      # Match, space is horizontal whitespace.
" "  =~  /\v/      # No match, space is not vertical whitespace.
"\r" =~  /\v/      # Match, a return is vertical whitespace.

"a"  =~  /\pL/     # Match, "a" is a letter.
"a"  =~  /\p{Lu}/  # No match, /\p{Lu}/ matches upper case letters.

"\x{0e0b}" =~ /\p{Thai}/  # Match, \x{0e0b} is the character
                          # 'THAI CHARACTER SO SO', and that's in
                          # Thai Unicode class.
"a"  =~  /\P{Lao}/ # Match, as "a" is not a Laotian character.

值得強調的是,\d\w 等會匹配單一字元,而不是完整的數字或字詞。若要匹配數字(由數字組成),請使用 \d+;若要匹配字詞,請使用 \w+。但請注意上述所提到的安全性考量。

括號字元類別

您可以在 Perl 正規表示式中使用的第三種字元類別形式是括號字元類別。在最簡單的形式中,它會列出可能匹配的字元,並以方括號括起來,如下所示:[aeiou]。這會匹配 aeiou 之一。與其他字元類別一樣,只會匹配一個字元。* 若要匹配由字元類別中所提到的字元組成的較長字串,請在字元類別後加上 量詞。例如,[aeiou]+ 會匹配一個或多個小寫英文母音。

在字元類別中重複字元不會產生任何效果;它只會被視為在集合中一次。

範例

"e"  =~  /[aeiou]/        # Match, as "e" is listed in the class.
"p"  =~  /[aeiou]/        # No match, "p" is not listed in the class.
"ae" =~  /^[aeiou]$/      # No match, a character class only matches
                          # a single character.
"ae" =~  /^[aeiou]+$/     # Match, due to the quantifier.

-------

* 括號字元類別僅匹配單一字元的例外情況有兩個。每個例外情況都需要 Perl 進行特殊處理才能正常運作

括弧字元類別中的特殊字元

正規表示式中大多數的元字元(即具有特殊意義的字元,例如 .*()會失去其特殊意義,且可以在字元類別中使用,而無需跳脫。例如,[()] 會比對開啟括弧或關閉括弧,且字元類別中的括弧不會進行分組或擷取。請注意,除非在單引號的內容中評估模式,否則變數內插會在解析括弧類別之前進行

$, = "\t| ";
$a =~ m'[$,]';        # single-quotish: matches '$' or ','
$a =~ q{[$,]}'        # same
$a =~ m/[$,]/;        # double-quotish: Because we made an
                      #   assignment to $, above, this now
                      #   matches "\t", "|", or " "

字元類別中可能具有特殊意義的字元為:\^-[],並在下方討論。它們可以使用反斜線跳脫,雖然有時不需要,在這種情況下可以省略反斜線。

序列 \b 在括弧字元類別中是特殊的。在字元類別之外,\b 是斷言,表示兩側都沒有兩個字元字元或兩個非字元字元的點,在括弧字元類別中,\b 會比對退格字元。

序列 \a\c\e\f\n\N{NAME}\N{U+hex char}\r\t\x 也很特殊,且具有與在括弧字元類別之外相同的意義。

此外,反斜線後接兩個或三個八進制數字會被視為八進制數字。

[ 在字元類別中並非特殊字元,除非它是 POSIX 字元類別的開頭(請參閱下方的 "POSIX 字元類別")。它通常不需要跳脫。

] 通常是 POSIX 字元類別的結尾(請參閱下方的 "POSIX 字元類別"),或表示方括號字元類別的結尾。如果您要將 ] 包含在字元組中,通常必須跳脫它。

但是,如果 ] 是方括號字元類別的第一個(或如果第一個字元是插入符號,則是第二個)字元,它不會表示類別的結尾(因為您不能有空類別),並且被視為可以不跳脫就配對的字元組的一部分。

範例

"+"   =~ /[+?*]/     #  Match, "+" in a character class is not special.
"\cH" =~ /[\b]/      #  Match, \b inside in a character class
                     #  is equivalent to a backspace.
"]"   =~ /[][]/      #  Match, as the character class contains
                     #  both [ and ].
"[]"  =~ /[[]]/      #  Match, the pattern contains a character class
                     #  containing just [, and the character class is
                     #  followed by a ].

方括號字元類別和 /xx 模式修改器

通常 SPACE 和 TAB 字元在方括號字元類別中沒有特殊意義;它們只是新增到類別配對的字元清單中。但是,如果 /xx 模式修改器生效,它們通常會被忽略,並且可以新增以提高可讀性。它們不能新增在單一結構的中央

/ [ \x{10 FFFF} ] /xx  # WRONG!

十六進位常數中央的 SPACE 是不合法的。

若要指定一個字面 SPACE 字元,您可以用反斜線跳脫它,例如

/[ a e i o u \  ]/xx

這會配對英文母音加上 SPACE 字元。

為了清楚起見,您應該已經使用 \t 來指定一個字面 tab,而 \t 不受 /xx 影響。

字元範圍

想要配對一系列字元並不少見。幸運的是,您可以使用連字號 (-) 來代替列出範圍中的所有字元。如果您在方括號字元類別中看到兩個字元以連字號分隔,它會被視為範圍中的所有字元都在類別中。例如,[0-9] 會配對任何 ASCII 數字,而 [a-m] 會配對 ASCII 字母表前半段的任何小寫字母。

請注意,連字符兩側的兩個字元不一定都是字母或數字。任何字元皆有可能,儘管不建議使用。['-?] 包含一系列字元,但大多數人不知道這些字元是什麼意思。此外,如果程式碼必須在使用不同字元集的平台(例如 EBCDIC)上執行,則此類範圍可能會導致可攜性問題。

如果字元類別中的連字符在語法上不能成為範圍的一部分,例如它是字元類別的第一個或最後一個字元,或者它緊接在一個範圍之後,則連字符不是特殊的,因此被視為一個要逐字比對的字元。如果您希望在字元集中比對連字符,並且其在類別中的位置可能被視為範圍的一部分,則必須使用反斜線來跳脫該連字符。

範例

[a-z]       #  Matches a character that is a lower case ASCII letter.
[a-fz]      #  Matches any letter between 'a' and 'f' (inclusive) or
            #  the letter 'z'.
[-z]        #  Matches either a hyphen ('-') or the letter 'z'.
[a-f-m]     #  Matches any letter between 'a' and 'f' (inclusive), the
            #  hyphen ('-'), or the letter 'm'.
['-?]       #  Matches any of the characters  '()*+,-./0123456789:;<=>?
            #  (But not on an EBCDIC platform).
[\N{APOSTROPHE}-\N{QUESTION MARK}]
            #  Matches any of the characters  '()*+,-./0123456789:;<=>?
            #  even on an EBCDIC platform.
[\N{U+27}-\N{U+3F}] # Same. (U+27 is "'", and U+3F is "?")

正如上面最後兩個範例所示,您可以使用 \N{...} 形式的範圍端點來實現與非 ASCII 平台的可攜性。這些表示指定的範圍將使用 Unicode 值來詮釋,因此 [\N{U+27}-\N{U+3F}] 表示要比對 \N{U+27}\N{U+28}\N{U+29}、...、\N{U+3D}\N{U+3E}\N{U+3F},無論它們的原生程式碼點版本為何。這些稱為「Unicode」範圍。如果任一端為 \N{...} 形式,則該範圍被視為 Unicode。如果另一個端點以非可攜式方式指定,則會在 "use re 'strict'" 下提出 regexp 警告

[\N{U+00}-\x09]    # Warning under re 'strict'; \x09 is non-portable
[\N{U+00}-\t]      # No warning;

以上兩個都比對字元 \N{U+00} \N{U+01}、... \N{U+08}\N{U+09},但 \x09 看起來像是一個錯誤,因此會為它提出警告(在 re 'strict' 下)。

Perl 也保證範圍 A-Za-z0-9 和這些範圍的任何子範圍與只會說英語的人在任何平台上預期相符。也就是說,[A-Z] 符合 26 個 ASCII 大寫字母;[a-z] 符合 26 個小寫字母;[0-9] 符合 10 個數字。子範圍,例如 [h-k],相應地符合,在這個情況下僅符合四個字母 "h""i""j""k"。這是 ASCII 平台上的自然行為,其中 "h""k" 的碼點(序數值)是連續整數 (0x68 到 0x6B)。但對於具有非 ASCII 原生字元集的平台,可能需要特別處理才能達成此目的。例如,在 EBCDIC 平台上,"h" 的碼點為 0x88,"i" 為 0x89,"j" 為 0x91,"k" 為 0x92。Perl 特別處理 [h-k] 以排除間隙中的七個碼點:0x8A 到 0x90。此特別處理僅在範圍是 ASCII 大寫、小寫和數字範圍之一的子範圍,且範圍的每一端都表示為文字,例如 "A",或表示為命名字元 (\N{...},包括 \N{U+... 形式) 時才會啟動。

EBCDIC 範例

[i-j]               #  Matches either "i" or "j"
[i-\N{LATIN SMALL LETTER J}]  # Same
[i-\N{U+6A}]        #  Same
[\N{U+69}-\N{U+6A}] #  Same
[\x{89}-\x{91}]     #  Matches 0x89 ("i"), 0x8A .. 0x90, 0x91 ("j")
[i-\x{91}]          #  Same
[\x{89}-j]          #  Same
[i-J]               #  Matches, 0x89 ("i") .. 0xC1 ("J"); special
                    #  handling doesn't apply because range is mixed
                    #  case

否定

也可以列出您不想符合的字元。您可以使用插入符號 (^) 作為字元類別中的第一個字元來執行此操作。例如,[^a-z] 符合任何不是 ASCII 小寫字母的字元,因此包含超過一百萬個 Unicode 碼點。該類別被稱為「否定」或「反轉」。

此語法使插入符號成為括號字元類別中的特殊字元,但僅當它是類別的第一個字元時。因此,如果您想要插入符號作為要符合的字元之一,請跳脫插入符號或不要將其列在第一個。

在反轉括號字元類別中,Perl 會忽略通常表示命名順序的 Unicode 規則,且某些字元應符合在不區分大小寫的 /i 符合下使用多個字元的順序。遵循這些規則可能會導致極為混淆的情況

"ss" =~ /^[^\xDF]+$/ui;   # Matches!

這應符合任何不是 \xDF 也不符合 \xDF/i 下符合的字元順序。"s" 不是 \xDF,但 Unicode 表示 "ss"\xDF/i 下符合的內容。那麼哪一個「獲勝」?您是否因為字串有 ss 而失敗符合,或因為它有一個 s 後面跟著另一個 s 而接受它?Perl 選擇了後者。(請參閱上方「括號字元類別」中的註解。)

範例

"e"  =~  /[^aeiou]/   #  No match, the 'e' is listed.
"x"  =~  /[^aeiou]/   #  Match, as 'x' isn't a lowercase vowel.
"^"  =~  /[^^]/       #  No match, matches anything that isn't a caret.
"^"  =~  /[x^]/       #  Match, caret is not special here.

反斜線順序

您可以在括號字元類別中放入任何反斜線順序字元類別(\N\R 例外),它將作用得好像您已將反斜線順序符合的所有字元都放入字元類別中。例如,[a-f\d] 符合任何十進制數字,或 'a' 到 'f'(含)之間的任何小寫字母。

\N 在方括號字元類別中必須為 \N{name}\N{U+hex char} 形式,且不能為與非換行符號相符的形式,原因與方括號字元類別中的點號 . 失去其特殊意義相同:它幾乎與任何東西相符,而這通常不是您想要的結果。

範例

/[\p{Thai}\d]/     # Matches a character that is either a Thai
                   # character, or a digit.
/[^\p{Arabic}()]/  # Matches a character that is neither an Arabic
                   # character, nor a parenthesis.

反斜線序列字元類別無法形成範圍的其中一個端點。因此,您不能說

/[\p{Thai}-\d]/     # Wrong!

POSIX 字元類別

POSIX 字元類別的格式為 [:class:],其中 class 為名稱,而 [::] 為分隔符號。POSIX 字元類別只會出現在方括號字元類別內部,且是列出字元群組的便利且具描述性的方式。

請小心語法,

# Correct:
$string =~ /[[:alpha:]]/

# Incorrect (will warn):
$string =~ /[:alpha:]/

後面的模式將會是一個字元類別,包含一個冒號,以及字母 alph

POSIX 字元類別可以是較大方括號字元類別的一部分。例如,

[01[:alpha:]%]

是有效的,且與 '0'、'1'、任何字母字元和百分比符號相符。

Perl 辨識下列 POSIX 字元類別

alpha  Any alphabetical character (e.g., [A-Za-z]).
alnum  Any alphanumeric character (e.g., [A-Za-z0-9]).
ascii  Any character in the ASCII character set.
blank  A GNU extension, equal to a space or a horizontal tab ("\t").
cntrl  Any control character.  See Note [2] below.
digit  Any decimal digit (e.g., [0-9]), equivalent to "\d".
graph  Any printable character, excluding a space.  See Note [3] below.
lower  Any lowercase character (e.g., [a-z]).
print  Any printable character, including a space.  See Note [4] below.
punct  Any graphical character excluding "word" characters.  Note [5].
space  Any whitespace character. "\s" including the vertical tab
       ("\cK").
upper  Any uppercase character (e.g., [A-Z]).
word   A Perl extension (e.g., [A-Za-z0-9_]), equivalent to "\w".
xdigit Any hexadecimal digit (e.g., [0-9a-fA-F]).  Note [7].

Unicode 屬性 相同,大部分 POSIX 屬性會相符,而不管是否啟用不區分大小寫 (/i) 相符。兩個例外是 [:upper:][:lower:]。在 /i 下,它們各與 [:upper:][:lower:] 的聯集相符。

大部分 POSIX 字元類別有兩個 Unicode 風格的 \p 屬性對應項目。(它們不是官方的 Unicode 屬性,而是衍生自官方 Unicode 屬性的 Perl 擴充項目。)下表顯示 POSIX 字元類別與這些對應項目的關係。

表中標籤為「ASCII 範圍 Unicode」的欄位中的其中一個對應項目只與 ASCII 字元集中的字元相符。

表中標籤為「全範圍 Unicode」的另一個對應項目與完整 Unicode 字元集中任何適當的字元相符。例如,\p{Alpha} 不僅與 ASCII 字母字元相符,也與整個 Unicode 字元集中任何被視為字母的字元相符。標籤為「反斜線序列」的欄位中的項目是一個 (簡短的) 等效項目。

[[:...:]]      ASCII-range          Full-range  backslash  Note
                Unicode              Unicode     sequence
-----------------------------------------------------
  alpha      \p{PosixAlpha}       \p{XPosixAlpha}
  alnum      \p{PosixAlnum}       \p{XPosixAlnum}
  ascii      \p{ASCII}
  blank      \p{PosixBlank}       \p{XPosixBlank}  \h      [1]
                                  or \p{HorizSpace}        [1]
  cntrl      \p{PosixCntrl}       \p{XPosixCntrl}          [2]
  digit      \p{PosixDigit}       \p{XPosixDigit}  \d
  graph      \p{PosixGraph}       \p{XPosixGraph}          [3]
  lower      \p{PosixLower}       \p{XPosixLower}
  print      \p{PosixPrint}       \p{XPosixPrint}          [4]
  punct      \p{PosixPunct}       \p{XPosixPunct}          [5]
             \p{PerlSpace}        \p{XPerlSpace}   \s      [6]
  space      \p{PosixSpace}       \p{XPosixSpace}          [6]
  upper      \p{PosixUpper}       \p{XPosixUpper}
  word       \p{PosixWord}        \p{XPosixWord}   \w
  xdigit     \p{PosixXDigit}      \p{XPosixXDigit}         [7]
[1]

\p{Blank}\p{HorizSpace} 為同義詞。

[2]

控制字元本身並不會產生輸出,但通常會以某種方式控制終端機:例如,換行和退格鍵就是控制字元。在 ASCII 平台上,ASCII 範圍內,碼點介於 0 到 31(含)加上 127(DEL)的字元為控制字元;在 EBCDIC 平台上,它們的對應字元為控制字元。

[3]

任何為圖形的字元,也就是可見的字元。此類別包含所有字母數字字元和所有標點符號字元。

[4]

所有可列印字元,也就是所有圖形字元加上那些並非控制字元的空白字元。

[5]

\p{PosixPunct} 和 ASCII 範圍內的 [[:punct:]] 符合所有非控制字元、非字母數字、非空白字元:[-!"#$%&'()*+,./:;<=>?@[\\\]^_`{|}~](雖然如果區域設定生效,它可能會改變 [[:punct:]] 的行為)。

名稱相似的屬性 \p{Punct} 在 ASCII 範圍內符合略有不同的集合,即 [-!"#%&'()*,./:;?@[\\\]_{}]。也就是說,它缺少九個字元 [$+<=>^`|~]。這是因為 Unicode 將 POSIX 視為標點符號的內容分成兩類:標點符號和符號。

\p{XPosixPunct} 和(根據 Unicode 規則)[[:punct:]],符合 \p{PosixPunct} 在 ASCII 範圍內符合的內容,加上 \p{Punct} 符合的內容。這與嚴格根據 \p{Punct} 符合的內容不同。另一種說法是,如果 Unicode 規則生效,[[:punct:]] 會符合 Unicode 視為標點符號的所有字元,加上 Unicode 視為符號的所有 ASCII 範圍字元。

[6]

從 Perl v5.18 開始,\p{XPerlSpace}\p{Space} 符合相同的內容。在較早的版本中,它們的唯一差別在於在非區域設定符合中,\p{XPerlSpace} 不符合垂直製表符 \cK。兩個僅限 ASCII 的範圍形式也相同。

[7]

與在許多書寫系統(例如泰文和梵文)中比對數字的 [[:digit:]] 不同,目前只有兩組十六進位數字,而且不太可能再新增更多。這是因為你需要的數字不僅是十個,還有六個 [A-F](和 [a-f])相應的數字。這表示只有拉丁字母適合這些數字,而 Unicode 只有兩組這些數字,即熟悉的 ASCII 組和從 U+FF10(全形數字零)開始的全形字型。

除了表格中列出的名稱之外,還可以有其他各種同義詞。例如,\p{XPosixAlpha} 可以寫成 \p{Alpha}。所有這些都列在 "perluniprops 中透過 \p{} 和 \P{} 存取的屬性" 中。

這兩個 \p 對應項都假設 Unicode 規則有效。在 ASCII 平台上,這表示它們假設 128 到 255 的碼點是 Latin-1,這表示在區域設定規則下使用它們是不明智的,除非區域設定保證是 Latin-1 或 UTF-8。相反地,POSIX 字元類別在區域設定規則下很有用。它們會受到實際規則的影響,如下所示

如果 /a 修飾詞有效 ...

每個 POSIX 類別比對的內容與它們的 ASCII 範圍對應項完全相同。

否則 ...
對於大於 255 的碼點 ...

POSIX 類別比對的內容與它的全範圍對應項相同。

對於小於 256 的碼點 ...
如果區域設定規則有效 ...

POSIX 類別會根據區域設定進行比對,但

word

也會包含平台的原生底線字元,無論區域設定為何。

ascii

在沒有 POSIX ascii 擴充功能的平台上,這只會比對該平台的原生 ASCII 範圍字元。

blank

在沒有 POSIX blank 擴充功能的平台上,這只會比對該平台的原生 tab 和空白字元。

如果改為使用 Unicode 規則 ...

POSIX 類別與全範圍對應類別比對結果相同。

否則 ...

POSIX 類別與 ASCII 範圍對應類別比對結果相同。

套用哪些規則的判定方式如 perlre 中的「哪個字元集修飾詞生效?」 所述。

POSIX 字元類別的否定

POSIX 字元類別的 Perl 擴充功能是可以否定它。這透過在類別名稱前加上插入符號 (^) 來執行。一些範例

    POSIX         ASCII-range     Full-range  backslash
                   Unicode         Unicode    sequence
-----------------------------------------------------
[[:^digit:]]   \P{PosixDigit}  \P{XPosixDigit}   \D
[[:^space:]]   \P{PosixSpace}  \P{XPosixSpace}
               \P{PerlSpace}   \P{XPerlSpace}    \S
[[:^word:]]    \P{PerlWord}    \P{XPosixWord}    \W

反斜線序列可以表示 ASCII 或全範圍 Unicode,這取決於各種因素,如 "Which character set modifier is in effect?" in perlre 中所述。

[= =] 和 [. .]

Perl 辨識 POSIX 字元類別 [=class=][.class.],但 (目前) 尚未支援它們。任何嘗試使用任一結構都會引發例外狀況。

範例

/[[:digit:]]/            # Matches a character that is a digit.
/[01[:lower:]]/          # Matches a character that is either a
                         # lowercase letter, or '0' or '1'.
/[[:digit:][:^xdigit:]]/ # Matches a character that can be anything
                         # except the letters 'a' to 'f' and 'A' to
                         # 'F'.  This is because the main character
                         # class is composed of two POSIX character
                         # classes that are ORed together, one that
                         # matches any digit, and the other that
                         # matches anything that isn't a hex digit.
                         # The OR adds the digits, leaving only the
                         # letters 'a' to 'f' and 'A' to 'F' excluded.

擴充方括號字元類別

這是一個精緻的方括號字元類別,可用於更易讀且不易出錯的類別,以及執行集合運算,例如交集。範例為

/(?[ \p{Thai} & \p{Digit} ])/

這將比對泰文腳本中的所有數字字元。

此功能在 Perl 5.18 中以實驗性質提供;在 5.36 中接受。

use re 'strict 使用的規則適用於此結構。

我們可以擴充上述範例

/(?[ ( \p{Thai} + \p{Lao} ) & \p{Digit} ])/

這會比對泰文或寮文腳本中的數字。

請注意這些範例中的空白。此結構在其中始終啟用 /xx 修改器。

可用的二元運算子為

&    intersection
+    union
|    another name for '+', hence means union
-    subtraction (the result matches the set consisting of those
     code points matched by the first operand, excluding any that
     are also matched by the second operand)
^    symmetric difference (the union minus the intersection).  This
     is like an exclusive or, in that the result is the set of code
     points that are matched by either, but not both, of the
     operands.

有一個一元運算子

!    complement

所有二元運算子都從左結合;"&" 的優先權高於其他所有優先權相等的運算子。一元運算子從右結合,且優先權最高。因此,這遵循 Perl 邏輯運算子的正常優先權規則。使用括號來覆寫預設優先權和結合性。

主要的限制是所有內容都是元字元。因此,您無法透過執行類似以下動作來參考單一字元

/(?[ a + b ])/ # Syntax error!

指定個別可輸入字元的最快方法是將其括在方括號中

/(?[ [a] + [b] ])/

(這與 [ab] 相同。)您也可以說等效的

/(?[[ a b ]])/

(當然,您可以使用 \x{...}\N{...} 等指定單一字元。)

最後一個範例顯示如何使用此建構來指定一般的方括號字元類別,而沒有額外的集合運算。請注意其中的空白。這是允許的,因為 /xx 會在此建構中自動開啟。

一般方括號字元類別接受的所有其他跳脫字元也都在這裡接受。

由於此建構會在 use re 'strict 下編譯,因此在一般類別中產生警告的無法辨識跳脫字元在此處是致命錯誤,以及這些類別元素的所有其他警告,以及目前在 re 'strict' 外部不會警告的一些做法。例如,您不能說

/(?[ [ \xF ] ])/     # Syntax error!

您必須在沒有大括號的 \x 後面有兩個十六進位數字(使用前導零來產生兩個)。這些限制是為了降低錯字導致類別與您認為它會匹配的內容不匹配的發生率。

如果一般的方括號字元類別包含 \p{}\P{},並與非 Unicode 碼點進行比對,可能會產生警告,因為結果不是 Unicode 定義的。使用此延伸表單時不會出現此類警告。

一般的方括號字元類別和這些類別之間的最後一個差異是,無法讓這些類別匹配多字元摺疊。因此,

/(?[ [\xDF] ])/iu

不匹配字串 ss

您不必將 POSIX 類別名稱括在雙重方括號中,因此以下兩個都可行

/(?[ [:word:] - [:lower:] ])/
/(?[ [[:word:]] - [[:lower:]] ])/

任何包含的 POSIX 字元類別,包括 \w\D 等,都尊重 /a(和 /aa)修飾詞。

請注意,(?[ ]) 是正規表示式編譯時間建構。在編譯包含正規表示式時任何嘗試使用在當時無法得知的事物都是致命錯誤。在實務上,這只表示三個限制

  1. use locale(或 /l 正規表示式修飾詞)的範圍內編譯時,此建構假設執行時間區域設定會是 UTF-8,而產生的模式總是使用 Unicode 規則。因此,是否匹配並不取決於實際執行時間區域設定,所以不會啟用污染。但如果執行時間區域設定結果不是 UTF-8,則會產生 locale 類別警告。

  2. 任何 使用者定義的屬性 在正規表示式編譯時都必須已經定義(但請注意,此結構可用於取代此類屬性)。

  3. 一個正規表示式,否則會使用 /d 規則編譯,且使用此結構將改用 /u。因此,此結構會告訴 Perl 您不想要包含它的整個正規表示式的 /d 規則。

請注意,跳過空白只適用於此結構的內部。構成初始 (?[ 的任何字元之間不得有任何空白。且封閉的 ]) 字元之間也不得有空白。

就像在所有正規表示式中,模式可以透過包含在正規表示式編譯時內插的變數來建構。但目前每個此類子元件都應該是已編譯的延伸方括號字元類別。

my $thai_or_lao = qr/(?[ \p{Thai} + \p{Lao} ])/;
...
qr/(?[ \p{Digit} & $thai_or_lao ])/;

如果您內插其他內容,模式仍可能編譯(或可能失敗),但如果編譯,它很可能不會按照您的預期運作

my $thai_or_lao = '\p{Thai} + \p{Lao}';
qr/(?[ \p{Digit} & $thai_or_lao ])/;

編譯為

qr/(?[ \p{Digit} & \p{Thai} + \p{Lao} ])/;

這不會產生某人閱讀原始碼時可能預期的效果,因為交集僅適用於 \p{Thai},不包括寮國語言。

由於 Perl 分析事物的方式,您的括號和方括號可能需要平衡,甚至包括註解。如果您遇到任何範例,請將它們提交至 https://github.com/Perl/perl5/issues,以便我們可以為此手冊頁提供具體範例。