再談 UTF-8

By | February 16, 2017

Unicode 自 2.0 到現在 6.0 都是 21 bits 編碼。UTF 就是實作把這個最大為 21 bits 的數字儲存。常見的 UTF 有 UTF-8、UTF-16 及 UTF-32。今次要再講講 UTF-8。

UTF-8 之所以流行是因為它跟 ASCII 兼容,”a” 字在 ASCII 及 UTF-8 時都是 0x61,但在 UTF-16 時卻是 0x00 0x61,當中 0x00 用 ASCII 解讀時會觸發 null-terminated。且儲存英文及數字只需使用 1 byte,比 UTF-16 節省一倍。雖然儲存中文字時,UTF-8 會比 UTF-16 用多較多空間,不過除非是全中文文章,否則中英混雜時,例如 HTML,用 UTF-8 一般會較有儲存大小上的好處。

UTF-8 能兼容 ASCII 之餘又能儲存大於 128 編碼的袐密在於可變位數,詳情可參看 淺談 Unicode、UTF-8、UTF-16 和 UTF-32

今次要講的是如何能得知 UTF-8 字串 (string) 的長度。這裡講的是從記憶體 byte array 入手。

int strlen_utf8(char *s)
{
 int i = 0, j = 0;
 while (s[i]){
  if ((s[i] & 0xc0) != 0x80) j++;
  i++;
 }
 return j;
}

0xc0 就是 11 00 00 00
0x80 就是 10 00 00 00

這裡就是看看字串的每個 byte 是否 10 開頭,如是 10 開頭,即只是前一個 byte 的 trailing (後續) bytes,是同一個字,所以 count 不會加 1。

看到這裡,不得不贊嘆 UTF-8 這個設計很聰明,就算可變位元也能 self-sync 及有效得知字串長度。