字元類:[...], [^...]

Baseline 已廣泛支援

此特性已相當成熟,可在許多裝置和瀏覽器版本上使用。自 ⁨2015 年 7 月⁩以來,各瀏覽器均已提供此特性。

字元類匹配自定義字元集中包含或不包含的任何字元。當v 標誌啟用時,它還可以用於匹配有限長度的字串。

語法

正則表示式
[]
[abc]
[A-Z]

[^]
[^abc]
[^A-Z]

// `v` mode only
[operand1&&operand2]
[operand1--operand2]
[\q{substring}]

引數

operand1, operand2

可以是單個字元、另一個用方括號括起來的字元類、一個字元類轉義、一個Unicode 字元類轉義,或使用 \q 語法的字串。

子字串

一個字面量字串。

描述

字元類指定方括號內的字元列表,並匹配列表中的任何字元。v 標誌極大地改變了字元類的解析和解釋方式。以下語法在 v 模式和非 v 模式下均可用:

  • 單個字元:匹配字元本身。
  • 字元範圍:匹配包含範圍內的任何字元。範圍由兩個字元指定,中間用連字元(-)分隔。第一個字元的字元值必須小於第二個字元。字元值是字元的 Unicode 碼點。由於 Unicode 碼點通常按字母順序分配,[a-z] 指定所有小寫拉丁字元,而 [α-ω] 指定所有小寫希臘字元。在非 Unicode 感知模式下,正則表示式被解釋為一系列 BMP 字元。因此,字元類中的代理對錶示兩個字元而不是一個;詳見下文。
  • 轉義序列:\b\-字元類轉義Unicode 字元類轉義以及其他字元轉義

這些語法可以出現任意次數,並且它們所代表的字元集是並集。例如,/[a-zA-Z0-9]/ 匹配任何字母或數字。

字元類中的 ^ 字首會建立一個補集。例如,[^abc] 匹配除了 abc 之外的任何字元。當 ^ 字元出現在字元類中間時,它是一個字面量字元 — 例如,[a^b] 匹配字元 a^b

詞法語法對正則表示式字面量進行非常粗略的解析,以便它不會在字元類中出現的 / 字元處結束正則表示式字面量。這意味著 /[/]/ 是有效的,無需轉義 /

字元範圍的邊界不能指定多個字元,這在使用字元類轉義時會發生。例如:

js
/[\s-9]/u; // SyntaxError: Invalid regular expression: Invalid character class

非 Unicode 感知模式下,如果字元範圍的其中一個邊界是字元類,則 - 會變成字面量字元。這是為了 Web 相容性而棄用的語法,不應依賴它。

js
/[\s-9]/.test("-"); // true

非 Unicode 感知模式下,正則表示式被解釋為一系列 BMP 字元。因此,字元類中的代理對錶示兩個字元而不是一個。

js
/[😄]/.test("\ud83d"); // true
/[😄]/u.test("\ud83d"); // false

/[😄-😛]/.test("😑"); // SyntaxError: Invalid regular expression: /[😄-😛]/: Range out of order in character class
/[😄-😛]/u.test("😑"); // true

即使模式忽略大小寫,範圍兩端的大小寫對於確定哪些字元屬於該範圍仍然很重要。例如,模式 /[E-F]/i 僅匹配 EFef,而模式 /[E-f]/i 匹配所有大寫和小寫 ASCII 字母(因為它涵蓋了 E–Za–f),以及 [\]^_`

非 v 模式字元類

v 模式字元類將大多數字符按字面量解釋,並且對其可包含的字元限制較少。例如,. 是字面量點字元,而不是萬用字元。唯一不能按字面量出現的字元是 \]-

  • 在字元類中,大多數轉義序列都受支援,除了 \b\B反向引用\b 表示退格字元而不是單詞邊界,而另外兩個會導致語法錯誤。要按字面量使用 \,請將其轉義為 \\
  • 字元 ] 表示字元類的結束。要按字面量使用它,請將其轉義為 \]
  • 連字元(-)字元,當用於兩個字元之間時,表示一個範圍。當它出現在字元類的開頭或結尾時,它是一個字面量字元。當它用於範圍的邊界時,它也是一個字面量字元。例如,[a-] 匹配字元 a-[!--] 匹配字元 !-,而 [--9] 匹配字元 -9。如果你想在任何地方按字面量使用它,你也可以將其轉義為 \-

v 模式字元類

v 模式下字元類的基本思想保持不變:您仍然可以使用大多數字符的字面量形式,使用 - 表示字元範圍,並使用轉義序列。v 標誌最重要的特性之一是字元類中的集合表示法。如前所述,普通字元類可以透過連線兩個範圍來表達並集,例如使用 [A-Z0-9] 表示“集合 [A-Z] 和集合 [0-9] 的並集”。然而,沒有簡單的方法可以表示字元集的其他操作,例如交集和差集。

使用 v 標誌,交集用 && 表示,減法用 -- 表示。兩者都不存在意味著並集。&&-- 的兩個運算元可以是字元、字元轉義、字元類轉義,甚至是另一個字元類。例如,要表示“不是下劃線的單詞字元”,您可以使用 [\w--_]。您不能在同一級別混合運算子。例如,[\w&&[A-z]--_] 是一個語法錯誤。然而,由於您可以巢狀字元類,您可以透過編寫 [\w&&[[A-z]--_]][[\w&&[A-z]]--_] 來明確(兩者都表示 [A-Za-z])。類似地,[AB--C] 是無效的,您需要編寫 [A[B--C]](這隻表示 [AB])。

v 模式下,Unicode 字元類轉義 \p 可以匹配有限長度的字串,例如表情符號。為了對稱性,常規字元類也可以匹配多個字元。要在字元類中寫入“字串字面量”,您需要將字串用 \q{...} 包裹起來。這裡唯一支援的正則表示式語法是析取——除此之外,\q 必須完全包含字面量(包括跳脫字元)。這確保了字元類只能匹配具有有限多種可能性的有限長度字串。

由於字元類語法現在更加複雜,因此更多的字元被保留並禁止以字面量形式出現。

  • 除了 ]\ 之外,如果以下字元表示字面量字元,則必須在字元類中進行轉義:()[{}/-|。此列表與語法字元列表有些相似,不同之處在於 ^$*+? 在字元類內部不保留,而 /- 在字元類外部不保留(儘管 / 可能會分隔正則表示式字面量,因此仍然需要轉義)。所有這些字元也可以在 u 模式字元類中選擇性地轉義。
  • 以下“雙標點”序列也必須轉義(但無論如何,沒有 v 標誌它們都沒有太大意義):&&!!##$$%%**++,,..::;;<<==>>??@@^^``~~。在 u 模式下,其中一些字元只能在字元類中以字面量形式出現,並在轉義時導致語法錯誤。在 v 模式下,當它們成對出現時必須轉義,但單獨出現時可以選擇轉義。例如,/[\!]/u 無效,因為它是一個恆等轉義,但 /[\!]/v/[!]/v 都有效,而 /[!!]/v 無效。字面量字元參考有一個詳細的表格,說明哪些字元可以轉義或不轉義出現。

補集字元類 [^...] 不可能匹配長度超過一個字元的字串。例如,[\q{ab|c}] 是有效的,並匹配字串 "ab",但 [^\q{ab|c}] 是無效的,因為不清楚應該消耗多少個字元。檢查是透過檢查所有 \q 是否包含單個字元以及所有 \p 是否指定字元屬性來完成的——對於並集,所有運算元必須是純字元;對於交集,至少一個運算元必須是純字元;對於減法,最左邊的運算元必須是純字元。該檢查是語法上的,不考慮實際指定的字元集,這意味著儘管 /[^\q{ab|c}--\q{ab}]/v 等同於 /[^c]/v,它仍然被拒絕。

補集字元類和不區分大小寫的匹配

不區分大小寫匹配透過對預期字元集和匹配字串進行大小寫摺疊來實現。指定補集字元類時,JavaScript 執行大小寫摺疊和補集的順序很重要。簡而言之,u 模式下的 [^...] 匹配 所有字元 - caseFold(原始),而 v 模式下的 [^...] 匹配 caseFold(所有字元) - caseFold(原始)。這確保了所有補集字元類語法,包括 [^...]\P\W 等,都能相互抵消。

考慮以下兩個正則表示式(為簡化起見,我們假設 Unicode 字元有三種:小寫、大寫和無大小寫,並且每個大寫字母都有唯一的小寫對應,反之亦然)

js
const r1 = /\p{Lowercase_Letter}/iu;
const r2 = /[^\P{Lowercase_Letter}]/iu;

r2 是雙重否定,似乎與 r1 等效。但實際上,r1 匹配所有小寫和大寫 ASCII 字母,而 r2 一個也不匹配。以下是逐步解釋:

  • r1 中,\p{Lowercase_Letter} 構造了一個包含所有小寫字元的集合。此集合中的字元隨後被大小寫摺疊為其小寫形式,因此它們保持不變。輸入字串也被大小寫摺疊為小寫。因此,"A""a" 都被摺疊為 "a" 並被 r1 匹配。
  • r2 中,\P{Lowercase_Letter} 首先構造一個包含所有非小寫字元的集合,即大寫字母和無大小寫字元。此集合中的字元隨後被大小寫摺疊為它們的小寫形式,因此字元集變為所有小寫字母和無大小寫字元。[^...] 否定了匹配,使其匹配在此集合中的任何內容,即大寫字母。然而,輸入仍然被大小寫摺疊為小寫,因此 "A" 被摺疊為 "a" 並且不被 r2 匹配。

這裡的主要觀察是,在 [^...] 否定匹配之後,預期的字元集可能不是大小寫摺疊後的 Unicode 字元集的子集,導致大小寫摺疊後的輸入不在預期的字元集中。在 v 模式下,所有字元集也被大小寫摺疊。\P 字元類本身在 v 模式下的工作方式也略有不同(請參閱Unicode 字元類轉義)。所有這些都確保了 [^\P{Lowercase_Letter}]\p{Lowercase_Letter} 嚴格等效。

示例

匹配十六進位制數字

以下函式確定字串是否包含有效的十六進位制數字

js
function isHexadecimal(str) {
  return /^[0-9A-F]+$/i.test(str);
}

isHexadecimal("2F3"); // true
isHexadecimal("beef"); // true
isHexadecimal("undefined"); // false

使用交集

以下函式匹配希臘字母。

js
function greekLetters(str) {
  return str.match(/[\p{Script_Extensions=Greek}&&\p{Letter}]/gv);
}

// 𐆊 is U+1018A GREEK ZERO SIGN
greekLetters("π𐆊P0零αAΣ"); // [ 'π', 'α', 'Σ' ]

使用減法

以下函式匹配所有非 ASCII 數字。

js
function nonASCIINumbers(str) {
  return str.match(/[\p{Decimal_Number}--\d]/gv);
}

// 𑜹 is U+11739 AHOM DIGIT NINE
nonASCIINumbers("𐆊0零1𝟜𑜹a"); // [ '𝟜', '𑜹' ]

匹配字串

以下函式匹配所有行終止符序列,包括行終止符字元和序列 \r\n (CRLF)。

js
function getLineTerminators(str) {
  return str.match(/[\r\n\u2028\u2029\q{\r\n}]/gv);
}

getLineTerminators(`
A poem\r
Is split\r\n
Into many
Stanzas
`); // [ '\r', '\r\n', '\n' ]

這個例子與 /(?:\r|\n|\u2028|\u2029|\r\n)/gu/(?:[\r\n\u2028\u2029]|\r\n)/gu 完全等效,只是更短。

\q{} 最有用的情況是在執行減法和交集時。以前,這可以透過多個先行斷言來實現。以下函式匹配不是美國、中國、俄羅斯、英國和法國國旗的旗幟。

js
function notUNSCPermanentMember(flag) {
  return /^[\p{RGI_Emoji_Flag_Sequence}--\q{🇺🇸|🇨🇳|🇷🇺|🇬🇧|🇫🇷}]$/v.test(flag);
}

notUNSCPermanentMember("🇺🇸"); // false
notUNSCPermanentMember("🇩🇪"); // true

這個例子大致等同於 /^(?!🇺🇸|🇨🇳|🇷🇺|🇬🇧|🇫🇷)\p{RGI_Emoji_Flag_Sequence}$/v,但可能效能更好。

規範

規範
ECMAScript® 2026 語言規範
# prod-CharacterClass

瀏覽器相容性

另見