Javascript Unicode:修飾符 "u" 和類 \p{...}

2023-02-17 11:00 更新

JavaScript 對(duì)字符串使用 Unicode 編碼。大多數(shù)字符使用 2 個(gè)字節(jié)編碼,但這種方式只能編碼最多 65536 個(gè)字符。

這個(gè)范圍不足以對(duì)所有可能的字符進(jìn)行編碼,這就是為什么使用 4 個(gè)字節(jié)對(duì)一些罕見(jiàn)的字符進(jìn)行編碼,比如 (數(shù)學(xué)符號(hào) X)或 (笑臉),一些象形文字等等。

下面是一些字符對(duì)應(yīng)的 Unicode 值:

字符 Unicode Unicode 中的字節(jié)數(shù)
a 0x0061 2
0x2248 2
0x1d4b3 4
0x1d4b4 4
0x1f604 4

所以像 a 和  這樣的字符占用 2 個(gè)字節(jié),而 , 和  的對(duì)應(yīng)編碼則更長(zhǎng),占用 4 個(gè)字節(jié)。

很久以前,當(dāng) JavaScript 被發(fā)明出來(lái)的時(shí)候,Unicode 編碼要更加簡(jiǎn)單:當(dāng)時(shí)沒(méi)有 4 個(gè)字節(jié)的字符。所以,有些語(yǔ)言功能現(xiàn)在仍無(wú)法正確處理它們。

比如 length 認(rèn)為這里有 2 個(gè)字符:

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

……但我們可以清楚地認(rèn)識(shí)到這里只有一個(gè)字符,對(duì)吧?關(guān)鍵在于 length 把 4 個(gè)字節(jié)當(dāng)成了 2 個(gè) 2 字節(jié)長(zhǎng)的字符。這是不對(duì)的,因?yàn)樗鼈儽仨毐划?dāng)作一個(gè)整體來(lái)考慮(即所謂的“代理對(duì)(surrogate pair)”,你可以在 字符串 中閱讀關(guān)于代理對(duì)的更多信息)。

默認(rèn)情況下,正則表達(dá)式也會(huì)把一個(gè) 4 個(gè)字節(jié)的“長(zhǎng)字符”當(dāng)成一對(duì) 2 個(gè)字節(jié)長(zhǎng)的字符。正如在字符串中遇到的情況,這將導(dǎo)致一些奇怪的結(jié)果。我們很快會(huì)在后面的章節(jié) 集合和范圍 [...] 中遇到。

與字符串有所不同的是,正則表達(dá)式有一個(gè)修飾符 u 被用以解決此類問(wèn)題。當(dāng)一個(gè)正則表達(dá)式帶有這個(gè)修飾符后,4 個(gè)字節(jié)長(zhǎng)的字符將被正確地處理。同時(shí)也能夠使用 Unicode 屬性進(jìn)行查找了,我們接下來(lái)就一起學(xué)習(xí)它吧。

Unicode 屬性 \p{…}

Unicode 中的每個(gè)字符都有很多屬性。它們描述了字符所屬的“類別”,包含了關(guān)于字符的各種信息。

例如,如果一個(gè)字符具有 Letter 屬性,這意味著這個(gè)字符歸屬于(任意語(yǔ)言的)字母表。而 Number 屬性則表示這是一個(gè)數(shù)字:也許是阿拉伯?dāng)?shù)字,亦或是中文數(shù)字,等等。

我們可以查找具有某種屬性的字符,寫作 \p{…}。為了使用 \p{…},一個(gè)正則表達(dá)式必須使用修飾符 u

舉個(gè)例子,\p{Letter} 表示任何語(yǔ)言中的一個(gè)字母。我們也可以使用 \p{L},因?yàn)?nbsp;L 是 Letter 的一個(gè)別名。對(duì)于每種屬性而言,幾乎都存在對(duì)應(yīng)的縮寫別名。

在下面的例子中會(huì)找出來(lái) 3 種字母:英語(yǔ)、格魯吉亞語(yǔ)和韓語(yǔ)。

let str = "A ? ?";

alert( str.match(/\p{L}/gu) ); // A,?,?
alert( str.match(/\p{L}/g) ); // null(沒(méi)有匹配項(xiàng),因?yàn)闆](méi)有修飾符 "u")

以下是主要的字符類別和它們對(duì)應(yīng)的子類別:

  • 字母(Letter)L
    • 小寫(lowercase)Ll
    • 修飾(modifier)Lm,
    • 首字母大寫(titlecase)Lt,
    • 大寫(uppercase)Lu,
    • 其它(other)Lo。
  • 數(shù)字(Number)N
    • 十進(jìn)制數(shù)字(decimal digit)Nd,
    • 字母數(shù)字(letter number)Nl
    • 其它(other)No。
  • 標(biāo)點(diǎn)符號(hào)(Punctuation)P
    • 連接符(connector)Pc
    • 橫杠(dash)Pd,
    • 起始引號(hào)(initial quote)Pi,
    • 結(jié)束引號(hào)(final quote)Pf,
    • 開(kāi)(open)Ps,
    • 閉(close)Pe
    • 其它(other)Po。
  • 標(biāo)記(Mark)M(accents etc):
    • 間隔合并(spacing combining)Mc,
    • 封閉(enclosing)Me,
    • 非間隔(non-spacing)Mn。
  • 符號(hào)(Symbol)S
    • 貨幣(currency)Sc
    • 修飾(modifier)Sk,
    • 數(shù)學(xué)(math)Sm,
    • 其它(other)So。
  • 分隔符(Separator)Z
    • 行(line)Zl,
    • 段落(paragraph)Zp
    • 空格(space)Zs。
  • 其它(Other)C
    • 控制符(control)Cc,
    • 格式(format)Cf,
    • 未分配(not assigned)Cn,
    • 私有(private use)Co,
    • 代理偽字符(surrogate)Cs

因此,比如說(shuō)我們需要小寫的字母,就可以寫成 \p{Ll},標(biāo)點(diǎn)符號(hào)寫作 \p{P} 等等。

也有其它派生的類別,例如:

  • AlphabeticAlpha),包含了字母 L,加上字母數(shù)字 Nl(例如 Ⅻ —— 羅馬數(shù)字 12),加上一些其它符號(hào) Other_AlphabeticOAlpha)。
  • Hex_Digit 包括 16 進(jìn)制數(shù)字 0-9a-f。
  • ……等等。

Unicode 支持很多不同的屬性,列出整個(gè)清單需要占用大量的篇幅,因此在這里列出相關(guān)的鏈接:

舉例:16 進(jìn)制數(shù)字

舉個(gè)例子,讓我們來(lái)查找 16 進(jìn)制數(shù)字,寫作 xFF 其中 F 是一個(gè) 16 進(jìn)制的數(shù)字(0…9 或者 A…F)。

一個(gè) 16 進(jìn)制數(shù)字可以表示為 \p{Hex_Digit}

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

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

舉例:中文字符

讓我們?cè)賮?lái)查找中文字符。

有一個(gè) Unicode 屬性 Script(一個(gè)書寫系統(tǒng)),這個(gè)屬性可能有一個(gè)值:CyrillicGreek、Arabic、Han(中文)等等,這里是一個(gè)完整的列表。

要在給定的書寫系統(tǒng)中查找字符,我們需要使用 Script=<value>,例如對(duì)于西里爾字母:\p{sc=Cyrillic},中文象形文字:\p{sc=Han},等等。

let regexp = /\p{sc=Han}/gu; // 返回中文象形文字

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

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

舉例:貨幣

表示貨幣的字符,例如 $、 和 ,具有 Unicode 屬性 \p{Currency_Symbol},縮寫為 \p{Sc}。

讓我們用它來(lái)查找格式為“貨幣,接著是一個(gè)數(shù)字”的價(jià)格:

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

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

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

稍后,在文章 量詞 +, *, ? 和 {n} 中我們將學(xué)習(xí)如何查找包含很多位的數(shù)字。

總結(jié)

修飾符 u 表示啟用正則表達(dá)式中對(duì) Unicode 的支持。

這意味著兩件事:

  1. 4 個(gè)字節(jié)長(zhǎng)的字符被以正確的方式處理:被看成單個(gè)字符,而不是 2 個(gè) 2 字節(jié)長(zhǎng)的字符。
  2. Unicode 屬性可以被用于查找:?\p{…}?。

有了 unicode 屬性我們可以查找給定語(yǔ)言中的詞,特殊字符(引用,貨幣)等等。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)