[web] 瞭解網頁中看不懂的編碼:Unicode 在 JavaScript 中的使用
keywords: unicode
, utf-8
, JavaScript
如果只是想要簡單知道 Unicode 是什麼,沒有要瞭解使用方式的話,可以觀看計算機科學速成課(第四集):二進制 ,在此教學影片的後半段有提到文字符號的編碼概念。
在學習網頁開發的過程中,一定會慢慢的碰到所謂的 Unicode
, UTF-8
還有其他幾種不同的編碼方式,這麼說你可能不會太有感覺,讓我們以 Facebook 為例,你可以看到在資料傳遞的過程中,常常有這種看不太懂的東西...
我們把它拿出來編排一下大概長這樣:
"profiles": {
"768320183253420": {
"name": "PJCHENder\u7db2\u9801\u524d\u7aef\u8cc7\u6e90\u7ad9",
"firstName": "PJCHENder\u7db2\u9801\u524d\u7aef\u8cc7\u6e90\u7ad9",
"gender": 11,
"uri": "https:\/\/www.facebook.com\/pjchender\/",
"type": "page",
"businessID": 0,
"businessName": null,
"allBusinessData": [
{
"businessID": 0,
"businessName": null
}]
},
// ...
}
你可以看到裡面有 \u7db2\u9801\u524d\u7aef\u8cc7\u6e90\u7ad9
這種看不太懂的內容。
再舉一個例子來看,有些時候我們可能看到某些網路文章想要分享給別人,明明網址是:https://today.line.me/tw/pc/article/冰火之國+冰島-ownNlj
,可是一分享出去卻變成一堆看似亂碼的東西 https://today.line.me/tw/pc/article/%E5%86%B0%E7%81%AB%E4%B9%8B%E5%9C%8B+%E5%86%B0%E5%B3%B6-ownNlj
:
上面的這些例子都是文字轉成編碼後的情況,你應該可以瞭解到這些編碼在瞭解網頁開發時的重要性的,如果不懂的話,就無法把這些內容解碼回去,那就會看不懂別人的內容阿...
看到編碼卻不知道怎麼解碼,那該怎麼上車呢?
在這篇文章中會說明在網頁中常用的一些編碼方式,讓對網頁編碼沒有概念的捧油們可以對它有些概念,重點是對它不再畏懼,然後有興趣的話可以在透過延伸閱讀中的文章進一步瞭解更多細節。
什麼是字串編碼(String Encode)?
先來談談什麼是字串編碼,字串編碼簡單來說,就是把我們熟悉的文字用許多數字來代表它,你可以想像就像在當兵或坐牢的時候,大家不會直接叫你的名字,而是叫你的編號。
例如,「阿童」在坐牢時的編號是「9453」,這時候只要廣播「9453」請到司令台集合,阿童就會知道這是在叫他,就會跑到司令台來了。
這個編號是不會重複的,也就是「9453」就只會是「阿童」的編號,不會同時有其他淡水阿婆、基隆阿公的編號也一樣是 9543。
能夠代表你的身份證字號也是一種編碼的概念,這個編號就可以用來代表它指稱的是你。
電腦只認得數字
接著你可能會好奇,在監獄裡面因為方便管理、去個人化等因素,所以把人名改成編碼似乎合理,但為什麼需要把我們常用的文字也都變成編碼呢?
這是因為電腦在運算的過程中,底層都還是數字來表示的,電腦只看得懂數字,但並不認得文字符號。也就是它只看的懂「9453」這個數字,但並不認得「阿童」這些字。
更精確的說,電腦只認得「二進制」這種用 0 和 1 組成的數字。
由於電腦只認得數字,但是我們人類看得懂、使用的卻是文字,那麼該怎麼辦呢?於是,美國最早定義了一套文字符號的 編碼,能夠將每個英文的文字符號(Symbol)都對應到一個數字,這個最早統一的規定就稱為「ASCII 編碼」。
**文字符號(Symbol)**指的是可以把文字拆成的最小單位,像是英文的「字母」
a
,b
,c
都是文字符號;而中文的「國字」,像是人
,國
,正
這些也都是文字符號。
ASCII 編碼(ASCII Code)
ASCII Code 是由美國制訂,最早用來統一英文文字符號和數字間的對應關係,除了 52 個大小寫英文字母外,其中也包含了常用的符號(如 !
, <
, =
)和特殊字元,總共定義了 127 個關係。
舉例來說,從下面的 ASCII Table 中可以看到,最上面的地方寫了 Dec 和 Char,其中 Char
就是文字符號的部分,Dec
則是用來表示該文字符號的十進位數字,在這張表中可以看到大寫英文字母的 A
對應到的編號竟是十進位的 65
號,小寫英文字母 a
則是對應到十進位的 97
號:
完整的 ASCII Table 可以點這裡。
那麼 ASCII 的編碼方式就是我們最前面提到的, Facebook 中回傳的 \u9673\u67cf\u878d
內容嗎?答案是:「有關但不同」。
Unicode(萬國碼)
在最前面所提到 Facebook 中回傳的 \u9673\u67cf\u878d
其實用的是 Unicode 編碼?Unicode 編碼又是什麼呢?
你可以發現在 ASCII 中定義了 127 個文字符號和數字之間的關係,但是那是因為英文只需要有 26 個英文字母就可以組成各是各樣的單字,但是中文或者說許多國家的語言並不是這樣阿,很明顯的 ASCII Code 不適用於所有的語言。
此外,如果不同國家使用不同的編碼來表徵自己的文字符號,又會變得非常不方便,例如,在台灣「9453」這個數字代表「阿童」,同樣的數字「9453」在美國代表「阿普」,在韓國「9453」則代表的是「金秘書」,這樣真的是非常的不方便阿!有沒有辦法讓全世界有一個共用的罪犯編號不會重複,讓 9453 就只能代表阿童呢?
於是,讓各語言的文字符號都能用一個數字代表它,而且這個數字是世界通用且不會重複的,就出現了所謂的 Unicode(萬國碼)這個編碼。Unicode 就像一個世界通用的大字典,收納了好幾百萬個全世界的文字符號,且每一個文字符號都有一個屬於自己的編號。不會同一個編號在台灣、美國、日本卻表示不同的文字符號。
Unicode 就像一個世界通用的大字典,收納了好幾百萬個全世界的文字符號,且每一個文字符號都有一個屬於自己的編號,在 Unicode 的官網 http://www.unicode.org/ 中列出了所有的 Unicode。
用來表示數值的不同方式:談談進位制
這裡我們要先稍微跳開一下文字編碼的部分,來談一下進位制。
因為電腦只認得數字(0
和 1
),因此不論是 ASCII 或 Unicode,都是把數字和文字符號間做一對一的轉換,因此都可以把文字轉換成對應到的數字,但是用來表示數字的方式則有很多種,我們把它稱為進位制,像是二進制、八進制、十進制和十六進制等等。
由於在 Unicode 中多數使用十六進制的方式來表示一個數值,因此在這裡先簡單說明進位制的概念和轉換。
不同進位制的表示
在這裡我們不會說明進位制之間轉換的計算方式,而是說明如何用 JavaScript 或工具進行數字間不同進位制的轉換,先來簡單瞭解不同進位制的表示方式:
二進制(Binary;bin):只用 0
和 1
這兩個數字表示一個數值的方式就稱為二進制,因此最後要給電腦看的數值最終都將轉為二進制(Binary)。在 JavaScript 中,如果你要告訴程式這是一個二進制的數字,需在數字的最前面加上 0b
。
八進位(Octal;oct):只用 0
, 1
, ... 7
這八個數字來表示一個數值的方式 稱為八進制。在 JavaScript 中,如果你要告訴程式這是一個八進制的數字,需在數字的最前面加上 0
或 0o
。
十進位(Decimal;dec):這是平常使用的數字表示法,只用 0
, 1
, ... 9
這十個數字來表示一個數值的方式稱為十進制。在 JavaScript 中,如果你要告訴程式這是一個十進制的數字,你什麼都不必做,直接輸入的數字就是表示十進制。
十六進位(Hexadecimal;hex): 只用 0
, 1
, ..., 9
, A
, B
, C
, D
, E
, F
這十六個是數字來表示一個數值的方式稱為十六進制,其中 A 表示十進制中的 10
, B 表示十進制中的 11
,F 表示十進制中的 15
,以此類推。在色碼的表示上,也常使用十六進制的數字(如,#FF00AA
)來表示一個顏色。在 JavaScript 中,如果你要告訴程式這是一個十六進制的數字,需在數字的最前面加上 0x
。
使用十六進制的好處是,可以使用較少的位數就能表示更多的數值,例如十六進制的兩位數的
FF
就表示在十進制的需要用三位數表示的255
。
進位制(縮寫) | 前綴法(JavaScript) | 下標表示法 |
---|---|---|
二進位(Binary;bin) | 0b 11111110 | (11111110) |
八進位(Octal;oct) | 0 376, 0o 376 | (376) |
十進位(Decimal;dec) | 254 | (254) |
十六進位(Hexadecimal;hex) | 0x fe | (fe) |
使用 JavaScript 進行不同進位制間的轉換
將不同進位制的數值轉為十進位:Number()
在 JavaScript 中要把不同進位制的數值轉換成十進制非常容易,只需要在該數值前讓 JavaScript 知道該數值是什麼進位制(例如,0x
, 0b
)接著使用 Number()
函式即可。
在下面的例子中,9453
, 10010011101101
, 22355
, 24ed
這些不同進位制的數字在轉換後其實都是表示十進制的 9453
:
/* 使用 Number() 將不同進位制的數值轉為 10 進位 */
Number('9453'); // 回傳 9453,直接帶入就是 10 進制
Number('0b10010011101101'); // 回傳 9453,以二進制的的前綴法 0b 表示
Number('022355'); // 回傳 9453,以舊八進制的前綴法 0 表示
Number('0o22355'); // 回傳 9453,以新的八進制的前綴法 0o 表示
Number('0x24ed'); // 回傳 9453,以十六進制的的前綴法 0x 表示
你會發現,十六進位制(
24ed
)比起二進位制(0b10010011101101
),明顯只需要較少的位數就能表示同一個數值。
除了使用 Number()
函式外,使用 Number.parseInt(string, radix)
也能達到轉換的效果:
// 指定該內容要使用的進位制
parseInt('fe', 16); // 254, 0xfe = 254
parseInt('376', 8); // 254, 0o376 = 254
parseInt('11111110', 2); // 254, 0b11111110 = 254
若想進一步瞭解
Number.parseInt()
的用法,可參考parseInt()
在 MDN 上的說明。
將十進位轉換為不同進位制:toString()
如果想要將十進位的數值轉換成其他進位制的話,可以使用 Number.prototype.toString()
這個函式:
/* 使用 toString() 將十進位轉換成不同進位制 */
(9453)
.toString(2)(
// 回傳 '10010011101101',將 9453 轉換成 二 進制
9453,
)
.toString(8)(
// 回傳 '22355',將 9453 轉換成 八 進制
9453,
)
.toString(16); // 回傳 '24ed',將 9453 轉換成 十六 進制
進位制轉換工具
如果你想要看看自己轉換的結果正不正確,可以使用進位換算計算機這套小工具,我們平常用的是 10 進位的數字,所以只需要在十進位的地方輸入「9453」按下計算後,就會出現二進位的結果是「10010011101101」。