iT邦幫忙

4

Unicode 編碼說明

c#

Unicode 編碼

用白話來解釋, 說穿了, 電腦是一堆電路串在一起,
但什麼是電路呢?

簡單來說, 電路需要用到電, 通了電就是開, 沒通電就是關,
所以電路就是開關, 開代表1, 關代表0.

所以一條電路只有開和關, 如下圖所示: 一條電路下寫0, 表示關閉一條電路

0

打開一條電路, 則就是一條電路下寫1.

1

我們就用一條電路來表示數字, 關閉電路0就代表數字0, 關閉電路1就代表數字1.

接下來要表示數字2, 但光是一條電路不夠表示數字2, 就加上第二條電路來表示, 如下圖

10

上圖中的 "10" 就拿來表示數字2

以此類推, "11" 就表示數字3, 所以電腦就用很多條電路來表示數字. 故當數字越大, 所需要的電路就越多條. 例如很多條開關 "01010101" 就需要 8 條電路.

一條電路只有開和關兩種表示法, 所以稱為二進制.

電腦除了表示數字之外, 我們還需要電腦表示文字, 美國最早定義了一套文字符號的編碼, 能夠將每一個英文字母和各種特殊符號都對應到一個數字, 這個統一的數字規定就稱為 "ASCII 編碼". ASCII 編碼總共定義了 127 個數字.

但是許多國家的語言不是英文, 很明顯的除了 ASCII 編碼 127 個數字以外, 電腦還需要更多的數字來代表其他國家的語言.

所以就出現了所謂的 Unicode 這個編碼, 收納了好幾百萬個全世界的文字符號.

Unicode 編碼表示法例如

\u9673

以 '\u' 開頭表示為 Unicode 編碼, 後面跟著數字編號.

透過 Unicode 編碼讓所有國家的文字符號都可以在電腦內被辨認, 但是這個碼點範圍從 U+0000 到 U+10FFFF 很大.

假設某一個國家語言範圍在 Unicode 編碼範圍中只有一部分, 而如果電腦直接原封不動儲存 Unicode 原始格式編碼(UTF-32), 就會佔用太多不必要的空間.

故出現UTF-8, UTF-16 或 UTF-32, 它們都可以視為是 Unicode 實做的一種方式, 它們用不同的方式來規範要如何將 Unicode 中的碼點儲存在電腦中以被使用.

在網際網路上最常被使用的則是 UTF-8 的編碼方式, 而在 JavaScript 引擎中主要支援的則是 UTF-16.

回頭看 Unicode 編碼中的範圍是從 U+0000 到 U+10FFFF 超過 110 萬個文字符號, 因此又可分為兩種

  • 基本平面(BMP, Basic Multilingual Plane)

範圍從 U+0000 到 U+FFFF, 放了最常見的文字符號.

  • 輔助平面(SMP, Supplementary planes or Astral planes)

範圍從 U+010000 到 U+10FFFF, 又稱為補充平面

在 JavaScript 中顯示 Unicode 字元

在JavaScript 中的字串可以用以下內容表示 "只使用" 到 Unicode 基本平面(也就是只用到 U+0000 到 U+FFFF)

\u<碼點>

如果有使用到 Unicode 輔助平面時, 則要用下面表示, 加上大括號

\u{<碼點>}

若只使用到 ASCII 符號時, 則可以用以下內容表示

\x<碼點>

怎麼這麼亂!?
我一律通通用以下全部表示就好了...

\u{<碼點>}

如果想要在 CSS 中使用 Unicode,可以使用下面表示

\<碼點>

故在CSS 中就是用這方式表示 Unicode 內容

.content::before{
   content: '\0041';
}

C# 實作 Encode / Decode Unicode string

以下是將一般的字串內容轉成Unicode 表示法的內容

public string EncodeToUnicode(string srcText)
{
   string dst = "";
   foreach (var ch in srcText)
   {
      var bytes = Encoding.Unicode.GetBytes(ch.ToString());
      var str = @"\u" + bytes[1].ToString("x2") + bytes[0].ToString("x2");
      dst += str;
   }
   return dst;
}

以下是將 Unicode 內容轉回一般字串內容

public string DecodeUnicode(string srcText)
{
   string dst = "";
   string src = srcText;
   int len = srcText.Length / 6;

   for (int i = 0; i <= len - 1; i++)
   {
      var str = ExtractUnicodeNumberWord(src);
      src = ExtractRemaindingUnicodeWords(src);
      var bytes = new byte[2];
      bytes[1] = byte.Parse(Extract2Characters(str, 0));
      bytes[0] = byte.Parse(Extract2Characters(str, 2));
      dst += Encoding.Unicode.GetString(bytes);
   }
   return dst;
}

private static string ExtractUnicodeNumberWord(string src)
{
   return ExtractUnicodeWord(src).Substring(2);
}

private static string ExtractRemaindingUnicodeWords(string src)
{
   return src.Substring(6);
}

private static string ExtractUnicodeWord(string src)
{
   return src.Substring(0, 6);
}

private static string Extract2Characters(string str, int startIndex)
{
   return int.Parse(str.Substring(startIndex, 2), System.Globalization.NumberStyles.HexNumber).ToString();
}

1 則留言

0
perton
iT邦新手 1 級 ‧ 2019-08-13 15:29:49

精簡扼要的解說,給個"讃"

感謝吉言

我要留言

立即登入留言