編碼方式的介紹

by adonis 25. 八月 2014 17:04

編碼方式的介紹

作    者:楊先民
審    稿:張智凱

前言

常常聽到有人說,存在資料庫中的員工姓名,在網頁顯示時會出
現問號,不知道到底是什麼原因,所以本期就來探討一下編碼方
式的討論。

各種不同編碼方式

首先要先了解,資料庫存放資料,並不是直接存放中文字,或是英文字,而是存放所謂的「內碼」,然後作業系統要將字呈現出來時,會對自身的內碼表,然後顯示該呈現的字元出來。

舉例來說,假設中文字「楊」的內碼是「AA01」,在資料庫會存放的是 AA01,而不是楊這個中文字,而楊這個字要在別的作業系統呈現時,會尋找 AA01的內碼,然後對照相對的字,呈現在畫面上。

所以說,如果資料庫用的編碼方式是A,但是使用者端應用程式的作業系統所使用的編碼方式是 B,在B中自然找不到 A所存放的內碼,所以資料也就無法呈現了,而且並不是單純你的應用程式支援該編碼就代表字能夠正確的顯示,主要還是看作業系統。

像 Windows Server,自 2000之後全面支援 Unicode(不過應該推到更早,NT4就有),不過得看你有沒有安裝該國的 Unicode字集,如果沒有裝的話,還是會在畫面上呈現問號或是亂碼,所以並不是單純一句:支援 Unicode就代表所有亂碼問題都解決了。

那到底有多少編碼方式呢?介紹一下:

處理各語系的字,有許多種編碼方式,一般可分為 ANSI 及 Unicode這兩種:
而一般 Unicode 又可以再細分成 UTF-8, UTF-16, UTF-32, 一般我們俗稱的 Unicode 指的是 UTF-16而非 UTF-8,常看到的 UTF-8是網頁編碼時常用的規格。

先來看這不常用的 UTF-32吧,它又稱 UCS-4編碼,它對每一個 Unicode碼位使用32位元,不過它會何不常用呢?因為 UTF-32對每個字元都使用 4位元組,就空間而言相當的浪費而沒有效率,所以被提起的機會不高。

ANSI:


早期英語系的國家所使用的編碼方式,用來處理英文字母、數字及常用符號,只會佔用一個位元組,因為1個位元組有 8個 bits,排列組合從 00000000到11111111,已經能收錄全部英文字母、數字以及常用符號,所以只需要1個位元組,相當節省。

然而,若是要處理中文字,使用 ANSI是絕對不夠的,所以當年由中華民國財團法人資訊工業策進會與國內13家廠商合作進行「五大軟體專案」,這五大軟體分別是「文書處理」、「資料庫」、「試算表」、「通訊」以及「繪圖」,稱為五大碼或大五碼,以繁體中文字來說,可以收錄的繁體中文字大概有一萬三千多個字,所以每個繁體中文字就需要二個位元組來儲存,不同國別的字可能佔用位元組可能會更多,而這種每個字為可變的位元組方法,稱作「多位元組(Multiple Byte)」的編碼,當年 SQL Server 6.5就是所謂的「多位元組」的版本,可以用來處理中文資料,故多位元組的編碼不利程式讀取,因為英文字依然是使用1位元組,中文字使用多位元組,中英文混在一起常造成切割字元的問題,所以 SQL Server 6.5當年我在使用時,有個重大的缺點,就是預存程序儲存,如果全用英文編碼,連註解都是英文的話,則程式不會有問題,但若是註解有中文的話,則有時預存程序開啟,程式只剩下一半的怪異情況,當然這些問題在 SQL Server 2000之後就全部解決。


剛才提到, ANSI 不能完整解決所有的各種語系的國別字(萬國碼),若 ANSI 的檔案儲存 Big5 編碼方式, 就不能以 ANSI GBK(簡體中文)的方式開啟,因為 ANSI 的編碼,某個繁體中文字的二位元組內碼,也許是對印到簡體中文字的另一個字,甚至簡體中文字沒有對印到該二位組內容,所以用 BIG5 ANSI 來儲存,就不能用 GBK ANSI 來讀取,不然會造成亂碼, 不過英、數字母及常用符號,因為用同一個位元組內容儲存,就可以在不同 ANSI 編碼正確讀取。

UTF-16(Unicode):


為了處理多國語言所採用的方式,號稱所有國家的字都可以用此編碼來相容, 每個英文字、數字或其它國家的字統一用二個位元組, 以中文字「楊」為例,它在 UTF-16 中佔兩個二位元組,
用 C 語言的來表示「楊」的十六位元表示寫法為 0x4A 及 0x69,其中 0x4A 為低位組,0x69 為高位組,在 Windows 系統上則可能寫成 4A69,換句話說,就是由低位元組先寫,再寫入高位元組,而在 MAC 系統上則可能寫成 694A,也就是由高位元組先寫,再寫入低位元組, 假設有一份文字檔案是先寫低位元組再寫高位元組,稱作「UTF-16 LE(Little-Endian)」, 若是先寫高位組再寫低位組,稱作「UTF-16 BE(Big-Endian)」, 而為了分辨文字檔案中是何種 UTF-16,會在一份檔案的開頭一定會先寫 BOM(Byte Order Mark), 若開頭寫入 0xFF 再寫 0xFE 則為 UTF-16 LE 檔案格式, 若開頭寫入 0xFE 再寫 0xFF 則為 UTF-16 BE 檔案格式。
SQL Server中, XML的資料型別是支援 UTF-16。

image

UTF-8:


前面提到的 UTF-16是「標準.Unicode」,因為 UTF-16 不管在處理中文字,英文或是不同國家的字時,每個字都是佔兩個位元組, 而對於英語語系國家而言,只會使用到英文、數字及一些特殊符號時,本來用 ANSI 編碼只佔用一個位元組來處理, 但是若是存成 UTF-16 的編碼時,就會佔用二個位元組反而佔用空間, 所以 UTF-16 不利資料傳輸及太佔用系統儲存空間,為此所提出的一種解決方案,就是 UTF-8,採用 UTF-8 編碼時,會根據每個字它所對應的 Unicode 的範圍來決定每個字所佔用的位元組, 而每個字轉為 UTF-8 時,其所佔用的位元組可能為 1 ~ 6 位元組中的其中一種組合, 但是英、數及常用符號的話,每個字一定只會佔用一個位元組,其它國家的字就不一定如此,所以 UTF-8 對於英語系國家而言它的檔案會較小, 但使用其它國別的字時,可能會佔用二個位元組或是比二個位元組還大空間, 若檔案中的字太多不是英數等字,反而更佔空間, 且因為每個字佔用空間可以 1 ~ 6 位元組中的其中一種組合,反而不利程式使用, 故程式在讀取 UTF-8 格式時,一般情況會先將會轉成 UTF-16(Unicode),使每個字成為固定雙位元組,方便處理。

UTF-8 本身不需要 BOM 辨識,可以在讀取整個檔案就可以判斷它是否為 UTF-8,
而有另一種有 BOM 的 UTF-8 的存在,所以即便是 UTF-8,也有分這麼多種類的 UTF-8,而 SQL Server嚴格來說並不是支援 UTF-8,網頁呈現多半是使用 UTF-8,換句話說,如果你想把 UTF-8的網頁資料,轉存到 SQL Server中的 Unicode系統,必需要做一個轉換,幸好這個轉換會自動的進行,不需要寫程式的人操心,只需要設為為「Unicode即可」。

不過我們就另一個角度來看,應該程式端的環境,一定支援 Unicode嗎?若不支援的話該如何是好?微軟的 MSDN也提供了解決方案給我們:

image

這裡可以肯定的地方是, SQL Server所安裝的 Windows Server,一定是支援 Unicode的,所以不用管圖中的「伺服器非 Unicode」的情形,若你的用戶端也是支援 Unicode,則將會得到最好的效能,但若是用戶端是非 Unicode的話,則字碼要先進行轉換再存入資料庫中會比較好,不然會有問題。

有人說,SQL Server支援的 Unicode是所謂的 UTF-16,不過似乎微軟認為的是UCS-2,一般來說, UTF-16是 UCS-2的父集,若沒有surrogate code points的輔助,一般認為 UTF-16等於 UCS-2,故在維基百科中寫,若有軟體宣稱自己支援 UCS-2,則代表所儲存的字元不會超過2個 bytes的字集,這也就是為什麼 SQL Server的 Unicode,每個字元長度不會超過2個 bytes的原因。

這樣大家大概就了解,連 Windows環境如果要 Unicode自轉都有可能發生問題,更不用講異質資料庫之間的 Unicode的轉換問題,最常提到的就是 Oracle的字元轉到 SQL Server的字元亂碼問題,你只要了解 Oracle到底是支援什麼種類的 Unicode,轉換到 SQL Server中就大概知道會不會有問題了。

LAST

Tags:

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List