字符的旅程

字符的編、解碼

對於電腦而言,每個字符不過是用一串的編碼來表示,比如英文小寫字符 ‘a’

  • 在 ASCII 編碼方式中,以16進位數字 0x61 表示。
  • 在 Unicode 編碼方式則是16進位數字 00000061。
  • 在 UTF-8 編碼方式則是16進位數字 61。

以 VSCode 為例,但包含多數的文字編輯器,都可以選擇儲存的編碼類型,也可以選擇打開文件的解碼類型。當然理論上用什麼編碼儲存就要用相同之解碼器打開 UTF-8 就是一種世界通用的編碼格式,因為它支援所有不同語言使用到的文字,故大多數軟體預設的編、解碼方式都是 UTF-8。

而瀏覽器也是要讀取 HTML、CSS 等檔案進行渲染,因此也得知道這些檔案的儲存格式,而現在這些檔案多用 UTF-8 來編碼保存,所以瀏覽器也得用 UTF-8 來解碼內容。

何謂 Unicode? UTF-8 是?

旨在容納世界所有文字符號的國際標準編碼,使用 4 Bytes 為每個字元編碼。 然而這 4 Bytes 實際上是稱作 Unicode 碼位 (Code Point),雖代表獨一無二的字元,卻並非實際儲存到檔案的編碼。 實際儲存到檔案的則是要看 Unicode 採用哪種編碼格式。

Unicode 本身不限定存儲方式,但常見的編碼方式有:

  • UTF-8(可變長度編碼,1 ~ 4 Bytes)
  • UTF-16(通常用 2 或 4 Bytes)
  • UTF-32(固定 4 Bytes)

Unicode 碼位 (Code Point),雖不是直接儲存的數據,卻可以定位獨一無二的字元,碼位範圍是 U+0000 至 U+10FFFF。

對於絕大多數常用字符,其碼位都能用 2 Bytes 表示,即 4 個十六進數字表示(範圍在 U+0000 至 U+FFFF)。 因此,可以發現在 HTML、CSS 等檔案中引用 Unicode 字符時,格式都是只用 2 Bytes 的碼位表示,比如說 bullet point 的碼位為 U+2022。

一律建議使用 Unicode 的 UTF-8 編碼方式

UTF-8 是 Unicode 的一種編碼方式,優勢是每個字符佔用的大小是可變的,根據字符的 Unicode 編號範圍,每個字符所需的字節數從 1 到 4 Bytes 不等,顯而意見的好處是可以節省儲存空間。比如說:

  • bullet point 的碼位是 (U+2022),其 UTF-8 編碼是 3bytes 為:0xE2 0x80 0xA2。
  • 小寫英文字母 a 的碼位是 (U+0061),其 UTF-8 編碼只佔 1 byte 為: 0x61。

網頁開發者會使用碼位表示字符,而無須直接把 UTF-8 或其他編碼格式的編碼寫出來。

UTF-8 的優勢

UTF-8 的設計解決了以上問題,主要優勢包括:

  • 變長編碼,節省空間
    • 常用字符(ASCII 範圍內)只需 1 Byte。
    • 不常用的字符會用 2-4 Bytes 表示,符合實際使用的頻率分佈。
  • 向後兼容 ASCII: 舊系統可以直接讀取 UTF-8 中的 ASCII 字符,而不需要特殊處理,因為 UTF-8 中對 ASCII 字符的編碼一模一樣,也都是 1 byte。
  • 全球化支持: 可以表示所有 Unicode 字符,滿足全球多語言需求。
  • 錯誤檢測能力: UTF-8 的編碼設計能夠檢測許多常見的數據錯誤,提升了數據的可靠性。

字形庫

編碼集 <-> 字形庫 之間的關係為何?

Unicode 定義了每個字符的 Code Point 碼位。 而對於每一個 Unicode Code Point

  • Unicode 定義了其字符意義。
  • UTF-8 定義了其字符底層編碼 (是幾個 bytes,每個 byte 的值)。
  • 字形庫 定義了其字符形狀。

比如說 Unicode 碼位 U+2022

  • Unicode 定義其意義為 bullet point。
  • UTF-8 定義其編碼為 3 Bytes,編碼值為 0xE2 0x80 0xA2。
  • 根據選用的字形庫則決定了在螢幕上, bullet point 顯示的形狀。

所以真正定義字符形狀的是由字形庫。字形庫會去實現他所支援的 Unicode 碼位的字形,可能是 svg 圖,或者點陣圖等等。 當你套用不同字形庫時,同一個意義的字符可能長得不一樣。 當然,不可能有一個字形庫實現所有的 Unicode 字符,所以要注意自己想要的字符是否可以被多數的字形庫支援,盡量選用支援度高的。

特殊符號的使用

一般符號,比如說英文的 26 字母,或是中文的字符,都可以靠輸入法輸入編輯器中。 然而,總是有些時候需要一些特殊符號來標註或者作特定使用,然而卻是輸入法或者應用程式沒有直接支援的。 但是 Unicode 包含了所有字符的定義,我們大可去網路上找出該字符,然後在編輯器中使用它。

程式設計師在撰寫 HTML、CSS 檔案時,可以怎麼使用特殊符號呢? 一樣舉 bullet point 為例:

  1. CSS 檔案內可以寫 “\2022”
  2. 也可以寫 “•”;

第 1 種寫法, CSS 檔案中的 string 內使用 \ 是 Unicode 的轉譯符號,後面接 4 個位數 16 進制的碼位,表示特定字符。這種把碼位寫出來的方式,需把 ‘'、‘2’、‘0’、‘2’、‘2’ 都存入檔案,較占用檔案空間。以 UTF-8 較省空間的編碼保存檔案,也會占用 5 Bytes。

第 2 種寫法,直接寫 ‘•’,好處是省檔案空間,又可以直接看到是什麼符號。然而有時候你的輸入法或者編輯器程式,沒有內建幫你輸入特殊符號的功能,那你就得去找到這個符號來複製,然後用貼上的方式輸入了,這不是什麼問題。但有時候搞不好 vscode 使用的字型不支援這個符號,那就沒有對應的圖形樣式,則無法在編輯器上呈現,這時用第一種作法就比較好。

HTML、CSS、JavaScript 如何使用 Unicode

不同的語言或環境對於嵌入 Unicode 碼位的書寫格式有不同的要求。 比如 Unicode 碼位 U+2022,即 bullet point 在不同網頁語言下取用方式如下:

語言/環境 使用方式 解釋
HTML &#8226; HTML 實體,十進制形式。
HTML &#x2022; HTML 實體,十六進制形式。
CSS \2022 CSS 的簡化 Unicode 表示法,十六進制形式。
JavaScript \u2022 JavaScript 字符串的 Unicode 表示,十六進制形式。

比如說在 CSS 語言中的字元或字串中輸入"\2022",這個格式是 Unicode 轉義序列。

  • \ 是轉義符號,表示接下來是一個 Unicode 碼位。
  • 2022 是十六進制的 Unicode 字符值,對應某個字符的圖標。

編碼的設定

現代的 HTML 預設使用 UTF-8 作為字符編碼,只要在 中指定: <meta charset="utf-8">

<meta charset="utf-8"> 的主要目的,是明確告訴瀏覽器這個 HTML 文件使用的字符編碼是 UTF-8,以避免因編碼錯誤導致的文字亂碼問題。 即使文件本身已保存為 UTF-8 格式,仍然需要這個標籤來確保瀏覽器正確解讀文件的內容。 因為如果未在 中明確指定字符集,瀏覽器會根據:

  • HTTP 回應頭中的 Content-Type。(如 Content-Type: text/html; charset=ISO-8859-1)
  • 預設的字符編碼(如某些地區設置默認為 ISO-8859-1)。
  • 文件內容

等進行猜測,而如果猜測的編碼與實際編碼不符,就會導致亂碼。

CSS 本身不直接指定文件編碼,但它繼承 HTML 的編碼環境,一般也都是 UTF-8 啦。

實用的工具網站

通常實用的做法是直接找字形庫,依照嵌入的方式,複製其字符或者碼位。至於 UTF-8 編碼,對一般使用者來說較不重要,除非你是寫編輯器或瀏覽器的人,不然根本不需要去碰到底層編碼。或者是你單純想看看其編碼為何。

通常上瀏覽器,搜尋 UTF-8 符號,點開任意連結,複製想要的內容貼上即可。

工具網站

  • 字形庫 Themify

    • 不過這個的缺點是網頁上沒有直接顯示符號對應的碼位,但可以下載後再將字形檔案丟到 Font Drop 就可以查看字符跟 Unicode 位碼對照著看。
    • 但是有支援很多漂亮 icons 可以用阿! 可以看到這些 icons 的位碼,是 (U+exxx) 經查詢屬於 Private Use Area,所以要下載這個字形庫才有支援阿,其他的字形庫不見得有支援這個位碼。
  • symbol.cc,列出許多 Unicode Symbol。

    • 除了基本的 Code point,也直接顯示 HTML、CSS、JavaScript 嵌入的格式,相當貼心。
    • 連 Alt Code 都有,在 Windows 下可以按住 Alt 加上 Code 打出特殊文字。
    • 也可切換到 Encoding 頁面看各種編碼。
  • Font Drop: 支援拖曳 .ttf.woff 文件,檢視所有符號。