2022 年 8 月 5 日

Unicode: 旗標「u」和類別 \p{...}

JavaScript 使用 Unicode 編碼 編碼字串。大多數字元使用 2 個位元組編碼,但這最多只能表示 65536 個字元。

這個範圍不足以編碼所有可能的字元,因此一些罕見的字元使用 4 個位元組編碼,例如 𝒳(數學 X)或 😄(笑臉)、一些象形文字等等。

以下是某些字元的 Unicode 值

字元 Unicode Unicode 中的位元組計數
a 0x0061 2
0x2248 2
𝒳 0x1d4b3 4
𝒴 0x1d4b4 4
😄 0x1f604 4

因此,像 a 等字元佔用 2 個位元組,而 𝒳𝒴😄 的碼則較長,它們有 4 個位元組。

很久以前,在 JavaScript 語言被建立時,Unicode 編碼較為簡單:沒有 4 位元組字元。因此,某些語言功能仍會錯誤處理它們。

例如,length 認為這裡有兩個字元

alert('😄'.length); // 2
alert('𝒳'.length); // 2

…但我們可以看到只有一個,對吧?重點是 length 將 4 個位元組視為兩個 2 位元組字元。這是錯誤的,因為它們必須一起考慮(所謂的「代理對」,您可以在文章 字串 中閱讀它們)。

預設情況下,正規表示式也會將 4 位元組「長字元」視為一對 2 位元組字元。而且,就像字串一樣,這可能會導致奇怪的結果。我們稍後會在文章 集合和範圍 [...] 中看到這一點。

與字串不同,正規表示式有旗標 u,可以解決此類問題。使用此旗標,正規表示式可以正確處理 4 位元組字元。Unicode 屬性搜尋也會變為可用,我們稍後會了解它。

Unicode 屬性 \p{…}

Unicode 中的每個字元都有很多屬性。它們描述字元屬於哪個「類別」,並包含有關它的其他資訊。

例如,如果一個字元具有 Letter 屬性,表示該字元屬於任何語言的字母表。而 Number 屬性表示它是一個數字:可能是阿拉伯數字或中文數字,依此類推。

我們可以使用屬性搜尋字元,寫成 \p{…}。若要使用 \p{…},正規表示式必須有旗標 u

例如,\p{Letter} 表示任何語言的字母。我們也可以使用 \p{L},因為 LLetter 的別名。幾乎每個屬性都有較短的別名。

在下面的範例中,將找到三種字母:英文、喬治亞文和韓文。

let str = "A ბ ㄱ";

alert( str.match(/\p{L}/gu) ); // A,ბ,ㄱ
alert( str.match(/\p{L}/g) ); // null (no matches, \p doesn't work without the flag "u")

以下是主要的字元類別及其子類別

  • 字母 L
    • 小寫 Ll
    • 修飾符 Lm
    • 標題字 Lt
    • 大寫 Lu
    • 其他 Lo
  • 數字 N
    • 十進制數字 Nd
    • 字母數字 Nl
    • 其他 No
  • 標點符號 P
    • 連接符號 Pc
    • 破折號 Pd
    • 開引號 Pi
    • 閉引號 Pf
    • 開括號 Ps
    • 閉括號 Pe
    • 其他 Po
  • 符號 M(重音等)
    • 組合間距 Mc
    • 包圍 Me
    • 不佔位 Mn
  • 符號 S
    • 貨幣 Sc
    • 修飾符 Sk
    • 數學 Sm
    • 其他 So
  • 分隔符號 Z
    • Zl
    • 段落 Zp
    • 空白 Zs
  • 其他 C
    • 控制 Cc
    • 格式 Cf
    • 未分配 Cn
    • 私人使用 Co
    • 代理 Cs

因此,例如,如果我們需要小寫字母,我們可以寫 \p{Ll},標點符號:\p{P} 等。

還有其他衍生類別,例如

  • 字母Alpha),包括字母 L,加上字母數字 Nl(例如 Ⅻ – 羅馬數字 12 的字元),加上一些其他符號 其他字母OAlpha)。
  • 十六進制數字包括十六進制數字:0-9a-f
  • …等等。

Unicode 支援許多不同的屬性,其完整清單需要很大的空間,因此以下提供參考

範例:十六進制數字

例如,讓我們尋找寫成 xFF 的十六進制數字,其中 F 是十六進制數字(0…9 或 A…F)。

十六進制數字可以用 \p{Hex_Digit} 表示

let regexp = /x\p{Hex_Digit}\p{Hex_Digit}/u;

alert("number: xAF".match(regexp)); // xAF

範例:中文字形

讓我們尋找中文字形。

有一個 Unicode 屬性 Script(寫作系統),其值可能是:CyrillicGreekArabicHan(中文)等,以下是完整清單

要尋找特定寫作系統中的字元,我們應該使用 Script=<value>,例如對於西里爾字母:\p{sc=Cyrillic},對於中文字形:\p{sc=Han},等等

let regexp = /\p{sc=Han}/gu; // returns Chinese hieroglyphs

let str = `Hello Привет 你好 123_456`;

alert( str.match(regexp) ); // 你,好

範例:貨幣

表示貨幣的字元,例如 $¥,具有 Unicode 屬性 \p{Currency_Symbol},簡短別名:\p{Sc}

我們使用它來尋找「貨幣,後接數字」格式的價格

let regexp = /\p{Sc}\d/gu;

let str = `Prices: $2, €1, ¥9`;

alert( str.match(regexp) ); // $2,€1,¥9

稍後,在文章 量詞 +, *, ? 和 {n} 中,我們將看到如何尋找包含多個數字的數字。

摘要

旗標 u 啟用正規表示式中 Unicode 的支援。

這表示兩件事

  1. 4 位元組的字元正確處理:作為單一字元,而不是兩個 2 位元組字元。
  2. Unicode 屬性可以用於搜尋:\p{…}

使用 Unicode 屬性,我們可以尋找特定語言、特殊字元(引號、貨幣)等等的字詞。

教學地圖

留言

在留言前先閱讀這段文字…
  • 如果您有改善建議,請 提交 GitHub 問題 或發起 pull request,不要留言。
  • 如果您無法理解文章中的某個部分,請詳細說明。
  • 若要插入幾行程式碼,請使用 <code> 標籤,若要插入多行,請將它們包在 <pre> 標籤中,若要插入超過 10 行,請使用沙盒 (plnkrjsbincodepen…)