閱讀681 返回首頁    go 阿裏雲 go 技術社區[雲棲]


每個 JavaScript 開發者都該懂的 Unicode

英文原文標題:what-every-javascript-developer-should-know-about-unicode

(譯者注:本文含有Unicode輔助平麵的特殊字符,部分瀏覽器可能無法正確顯示,但並不影響理解文章內容。)

在動筆寫這篇文章之前,我得先懺悔一下:在很長一段時間裏我對Unicode充滿了恐懼。

每次遇到需要Unicode知識的編程問題時,我總是找一個hack方案來解決,但解決方案的原理我也不懂。

直到遇見一個需要深入了解Unicode知識才能解決的問題,我才停止了這種逃避。因為這個問題沒辦法應用特定情境的解決方案。

在努力讀了一大堆文章之後,我驚訝地發現Unicode並不難懂。好吧,確實是有些文章起碼得看3遍才能看懂。

但我發現Unicode標準不僅世界通用,而且十分優雅簡潔,隻不過要理解其中一些抽象概念有點困難。

如果你覺得理解Unicode很難,那麼是時候來麵對它了!其實它沒你想的那麼難。去沏一杯香濃的茶或咖啡吧,讓我們進入抽象概念、字符、星光平麵(輔助平麵)和代理對的世界。

本文首先會解釋Unicode中的基本概念,這是必需的背景知識。

然後會說明JavaScript如何解析Unicode,以及你可能踩到哪些坑。

你還會學到如何利用ECMAScript 2015的新特性來解決部分難題。

準備好了?那就燥起來吧!

目錄:

1 Unicode背後的思想

2 Unicode基本概念

  • 2.1 字符與代碼點
  • 2.2 Unicode平麵
  • 2.3 碼元
  • 2.4 代理對
  • 2.5 組合用字符

3 JavaScript中的Unicode

  • 3.1 轉義序列
  • 3.2 字符串比較
  • 3.3 字符串長度
  • 3.4 字符定位
  • 3.5 正則匹配

4 結語

1. Unicode背後的思想

首先問一個最基礎的問題:你是怎樣閱讀並理解這篇文章的?答案很簡單,因為你明白這些字以及由字組成的單詞的含義。

那你又是如何明白這些字的含義的呢?答案也很簡單,因為你(讀者)和我(作者)對於這些(呈現在屏幕上的)圖形與漢字(即含義)之間的聯係有著相同的認知。

對計算機來說這個原理也差不多,隻有一點不同:計算機不懂這些字(字母)的含義,隻是將其理解為特定的比特序列。

讓我們設想一個情景:計算機User1向計算機User2發送一條消息'hello'。

計算機並不知道這些字母的含義。所以計算機User1將消息'hello'轉換為一串數字序列0x68 0x65 0x6C 0x6C 0x6F,每個字母對應一個數字:h對應0x68, e對應0x65,等等。

接著將這些數字發送給計算機User2。

計算機User2收到數字序列0x68 0x65 0x6C 0x6C 0x6F後,使用同一套字母與數字的對應關係重建消息內容,'hello'就能正確地顯示出來了。

不同計算機之間對字母與數字之間對應關係的協議就是Unicode進行標準化的結果。

根據Unicode,h是一個名為LATIN SMALL LETTER H的抽象字符。這個抽象字符對應數字0x68,也就是一個標記為U+0068的代碼點。這些概念將在下一章中說明。

Unicode的作用就是提供一個抽象字符列表(字符集),並給每一個字符分配一個獨一無二的標識符代碼點(編碼字符集)。

2. Unicode基本概念

www.unicode.org網站提到:

Unicode為每一個字符分配一個專有的數字

不分平台

不分程序

不分語言

Unicode是一個世界通用的字符集,它定義了全世界大部分書寫體係的字符集,並為每一個字符分配了一個獨一無二的數字(代碼點)。

Unicode囊括了大部分現代語言、標點符號、附加符號(變音符)、數學符號、技術符號、箭頭和表情符號等。

Unicode第一版1.0於1991年10月發布,包含7161個字符。最新版9.0(2016年6月發布)則提供了128172個字符的編碼。

Unicode的通用性與開放性解決了過去一直存在的一個問題:供應商們各自實現不同的字符集和編碼規則,很難處理。

創建一個支持所有字符集和編碼規則的應用是十分複雜的。更不用說你選用的編碼可能不支持所有你需要的語言。

如果你覺得Unicode很難,那就想想如果沒有它編程會更難。

我還記得從前隨機選擇所需的字符集和編碼規則去讀取文件內容的時候。全靠人品啊!

2.1 字符與代碼點

  • 抽象字符(即文本字符)是用來組織、管理或表現文本數據的信息單位。

Unicode中的字符是一個抽象概念。每一個抽象字符都有一個對應的名稱,例如LATIN SMALL LETTER A。該抽象字符的圖像表現形式(glyph)是a。(譯者注:glyph即圖像字符)

  • 代碼點是指被分配給某個抽象字符的數字

代碼點以U+的形式表示,U+是代表Unicode的前綴,而是一個16進製數。例如U+0041和U+2603都是代碼點。

代碼點的取值範圍是從U+0000到U+10FFFF。

記住代碼點就是一個簡單的數字。思考有關Unicode的問題時要記得這一點。

代碼點就好像數組元素的下標。

Unicode的神奇之處就在於將代碼點與抽象字符關聯起來。例如U+0041對應的抽象字符名為LATIN CAPITAL LETTER A (表現為A),而U+2603對應的抽象字符名為SNOWMAN(表現為)

注意,並非所有的代碼點都有對應的抽象字符。可用的代碼點有114112個,但分配了抽象字符的隻有128237個。

2.2 Unicode平麵

  • 平麵是指從U+n0000到U+nFFFF的區間,也就是65536(1000016)個連續的Unicode代碼點,n的取值範圍是從016到1016。

這些平麵將Unicode代碼點分為17個大小相等的集合:

  • 平麵0包含從U+0000到U+FFFF的代碼點
  • 平麵1包含從U+**1**0000到U+**1**FFFF的代碼點
  • ...
  • 平麵16包含從U+**10**0000到U+**10**FFFF的代碼點 image

基本多文種平麵

平麵0比較特殊,被稱為基本多文種平麵或簡稱BMP。它包含了大多數現代語言的字符 (基本拉丁字母, 西裏爾字母, 希臘字母等)和大量的符號。

如上文所述,基本多文種平麵的代碼點取值範圍是從U+0000到U+FFFF,最多可以有4位16進製數字。

大多數時候開發者處理的都是BMP中的字符。它包含了大多數情況下的必需字符。

BMP中的一些字符:

  • e對應代碼點U+0065 抽象字符名: LATIN SMALL LETTER E
  • |對應代碼點U+007C 抽象字符名: VERTICAL BAR
  • ■對應代碼點U+25A0 抽象字符名: BLACK SQUARE
  • 對應代碼點U+2602 抽象字符名: UMBRELLA

星光平麵

BMP之後的16個平麵(平麵1,平麵2,…,平麵16)被稱為星光平麵或輔助平麵。

星光平麵的代碼點被稱為星光代碼點。這些代碼點的取值範圍是從U+10000到U+10FFFF。

星光代碼點可能會有5位或6位16進製數字:U+ddddd或U+dddddd。

來看幾個星光平麵裏的字符: