2012年6月3日 星期日

Unicode與Big5轉換

Unicode
大五碼 ( BIG5 ),是用一個數字來表示英文字母及一些符號的數碼。對歐美國家的文字來說,只需約一~兩百個就已足夠,這是因為他們的文字都是以字母拼成,而每種語言的字母個數不多,例如英文字母僅 26 個,再加上空白、標點符號、阿拉伯數字等等,不超過一百個。
一個位元組 ( byte ) 有 8 個位元,可以表示 0~255 之間的數值,也就是說可以表示 256 種 ( 28=256 ) 不同的數字,若一個數表示一個字母或符號,那麼 ASCII 碼用一個位元組的長度就已經夠了,後來 ASCII 果真以 7 個位元表示,而 IBM 推出 PC/XT 時,把 ASCII 擴充為 8 個位元寬,即為一個位元組的大小。像 ASCII 這種系統,我們稱之為『單位元組編碼系統』( SBCS,Single Byte Code System。也有人稱為『單位元組字集』,Single Byte Character Set )。
但對於中文,就嫌不夠了。常用的中文字保守估計也有數千個,因此得用兩個位元組來表示文字,2 個位元組共有 16 個位元,最多可以表示 216,亦即 65536 個數,像這種以 2 個位元組編碼的方式稱為『雙位元組編碼系統』( DBCS,Double Byte Code System,也有人稱為『雙位元組字集』,Double Byte Character Set )。早期中文電腦發展時,並沒有強而有力的國家標準編碼,所以造成每一家公司或機構所發展的編碼不同而不相容。到了中華民國 73 年,中華民國財團法人資訊工業策進會和五間電腦公司,宏碁、神通、佳佳、零壹及大眾,所共同發展一套中文的編碼系統,這五家電腦公司在當時是數一數二的大公司,其影響力可謂舉足輕重,而他們所發展的編碼系統就稱為大五碼 ( Big5 )。詳情見維基百科有關 Big5 的說明。
由於大五碼的誕生,使得中文編碼有依循的標準,後來在 DOS 系統中的倚天中文,Windows 3.1 以及 Windows 95/98/Me 都採用這先後採用這套編碼來處理正體中文。但是 Big5 碼所收錄的字太少,許多人名、地名並沒有包括在內。因此後來有許多機構在 Big5 的基礎上加以擴充。現今 ( 民國 80~95 年 ),使用正體中文的國家或地區,像中華民國、香港、新加坡以及海外華人的中文電腦,大多使用 Big5 碼。

倚天中文系統在 DOS 系統下執行的倚天中文,採用的就是 Big5 碼。倚天中文系統執行後,會常駐於記憶體裏。倚天中文顯示文字的原理與英文類似,請參考第三十章顯示記憶體的說明。倚天中文也是把 B800:0000 開始的記憶體當成顯示記憶體,偶數位址是存放 Big5 碼,奇數位址是存放顏色,例如假設在螢幕上左上角顯示綠色的『我學 ASSEMBLY。』這句話,那麼用 DEBUG.EXE 觀察位址 B800:0000,您會看見:
B800:0000 A7 02 DA 02 BE 02 C7 02 20 02 41 02 53 02 53 02 ........ .A.S.S. B800:0010 45 02 4D 02 42 02 4C 02 59 02 A1 02 43 02 20 00 E.M.B.L.Y...C. .
的記憶體內容,其中以白色標起來的 A7DA、BEC7 和 A143 分別是『我』、『學』和『。』的 Big5 碼,而位址 B800:0001、B800:0003、B800:0005、B800:0007 等內容為 02 的位元組是綠字黑底的顏色號碼 ( 參考附錄七的表一 )。或許您會問,如果改變 B800:0001 或 B800:0003 的內容,使它們不一樣,這樣是不是會變成同一個字,但左半部和右半部顏色不同?的確如此,您可以試試看。底下以列表方式說明:

當倚天中文常駐於記憶體後,如果它發現螢幕上的資料屬於 Big5 碼,倚天中文會以這個 Big5 碼查出字形檔中該字的字形,最後再依據字形把字顯示於螢光幕上,這一點與 ASCII 的碼是一樣的。
在倚天中文採用 Big-Endian 的方式存入記憶體。此外在 Big5 的純文字檔案裏,也是以 Big-Endian 方式存入磁碟,這點和 PC 的習慣不同。有關什麼是 Big-Endian?什麼是 Little-Enddian?請參閱後面的說明
在這種以 Big5 編碼系統中,如果遇到中英文混合資料時,有兩種選擇,一是像上面的例子,ASCII 與 Big5 混合使用,但這樣一個字元可能佔用一個位元組也可能兩個位元組,在計算字串長度時有點困難;另一種是完全採用 Big5 碼,遇到英文時也採用全形字體
Big5 碼的編碼方式是以筆畫順序為依據,若筆畫相同則依其部首的筆畫排序。您可以到 Openi18n 台灣網頁去查詢每個 Big5 碼所代表的中文字。

萬國碼 ( UNICODE )
緣起隨著網際網路的發達,電腦已不是一座座的孤島,常常需要藉由網路與外界相連,讀取國外的資料,而這些資料不一定是本國語言或英文,像是日文、泰文、阿拉伯文、俄文……等等。甚至有時希望能在同一份文件中,能包含數種文字。要達到這目標,就不能靠一種語文一種編碼的方式了。
為了解決這個難題,自民國 73 年開始,有兩個組織著手研究這個問題。其中一個是國際標準組織 ( ISO,International Organization for Standardization ) 與聯合國下屬的國際電氣技術委員會 ( IEC,International Electro-technical Commission ) 合組的工作小組,該小組草擬提出的 ISO 10646 標準草案。另一個組織是由 IBM、DEC、Sun、Xerox、Apple、MicroSoft、Novell 公司,共同出資成立的 Unicode 協會,該協會設立非營利的 Unicode 公司,並由該公司設計出適用全球的萬國碼 ( Universal Code;簡稱 Unicode,亦有人稱統一碼、單一碼或萬國碼 )。雖然一開始,這兩個組織的工作是各自發展的,但是最後他們體認到世界不需要有兩套編碼,否則豈不是陷於當初的困境?於是在民國 80 年左右,他們合併了雙方的成果變成 ISO 10646/Unicode 標準,提供全世界語言文字與符號的顯示、儲存、傳送等,不但避免了資源的浪費,也能落實統一全球文字交換標準的理想。
要把全球所有文字編碼,不是一件簡單的事情。據估計全世界約有不到七千種語言,但是有些語言只有聲音沒有文字,扣除這些語言,只算有文字的語言約有兩千多種。要把這些語言的每個字都編成碼也不是簡單的工作,因為到底有多少個文字或字母,誰也說不準。但編碼工作總是要繼續的,經過數十年的努力,辛勤的工作總算有的結果,在民國 82 年發表的 ISO 10646。

UCS-4在 ISO 10646 裏用四個位元組來編碼,因此稱為 UCS-4,UCS 是 Universal Multiple-Octet Coded Character Set 的縮寫,意義為多個八位元編碼的廣用文字集,4 代表 4 個位元組。ISO 10646 依位元組高低次序把每一位元組稱為群組 ( group )、字面 ( plane )、列 ( row )、格 ( cell )。群組的最高位元不使用,僅剩七個位元,由 00H~07FH 共 128 個,可分成 128 群組;次高位元組代表字面,所以每一群都有 256 個字面 ( 00~0FFH ),每個字面本應有 216,即 65536 個空間可容納文字 ( 每個文字得佔用一個空間,或稱一個碼位 ),但 ISO 10646 裏規定最後兩格不用,所以每個字面變成 65534 個字。依據這個規則,最多可以把 65534×128×256 =2,147,418,112,約二十一億個文字編成碼。有關群組、字面的說明,請參考下圖所示 ( 下圖參考 CNS11643 中文全字庫繪製而成 ):

UCS-2 與 BMP雖然 ISO 10646 裏用四個位元組來編碼,但是實際上,全球重要的語言已經有九成五以上都包含在第 00 群組的第 00 字面。所以為了考慮效率,在 ISO 10646 也特別規定第 00 群組的第 00 字面稱為『基本多語文字面』( Basic Multilingual Plane,簡稱 BMP ),如果所使用的文字都在 BMP 內,那麼就可以用兩個位元組來表示,以節省空間增進效率,像這種字集稱為 UCS-2,也因為效率,世界各國莫不想讓本國文字擠進 BMP 裏。說了這麼多,小木偶整理一下:在實際使用上,萬國碼可分為 UCS-2 與 UCS-4 兩種編碼方式,如果所使用的文字都在 BMP 上,那麼使用 UCS-2 就可以了,否則就必須使用 UCS-4。同一份文件或檔案裏只能選擇其中一種,不是 UCS-2 就是 UCS-4,不能混用,以免造成一個字不定長度的缺點。

世界最重要的幾種語言,如北京話 ( 約 八億六千萬人使用 )、英語 ( 約四億三千萬人使用 )、印地語 ( 印度所使用的語言,約三億兩千萬人使用 ) 等語言都已被編入 BMP 中。各語文所佔編碼範圍可以參考維基百科有關基本多語文字面與曾士熊先生所著 Unicode 與 ISO10646 的描述,而各字的編碼可到 www.unicode.org 檢閱。底下是依熊先生的文章所作的介紹:

0000~007Fh: C0 控制碼與基本拉丁字母區。其中 0000~001Fh 為 C0 控制碼,0020h 為空格 ( space ),0021~007Eh 為 ASCII 圖形字元……事實上,這 128 個字元碼只要把前 8 個位元去掉就是 ASCII 碼。

0080~00A0h: 控制碼區。0080~009Fh 為 C1 控制碼,00A0h 為不中斷空格 ( no-break space )
00A1~1FFFh: 拼音文字區。收容除基本拉丁字母以外的各種拼音文字字元,包括歐洲各國語言、希臘文、斯拉夫語文、希伯來文、阿拉伯文、亞美尼亞文、印度各地方言、馬來文、泰文、寮文、柬普寨文、滿文、蒙文、藏文、印地安語文等。
2000~2BFFh: 符號區。收容各種符號,包括標點符號、上下標、錢幣符號、數字、箭頭、數學符號、工程符號、光學辨識符號、帶圈或帶括符的文數字、表格繪製符號、地理圖示、盲用點字、裝飾圖形等。
2C00~2E7Fh: 拼音文字區,包含格拉哥里字母、古埃及文、衣索匹亞語等…
2E80~33FFh: 中日韓符號區。收容康熙字典部首、中日韓輔助部首、注音符號、日本假名、韓文音符,中日韓的符號、標點、帶圈或帶括符文數字、月份,以及日本的假名組合、單位、年號、月份、日期、時間等。
3400~4DFFh: 中日韓認同表意文字擴充 A 區,總計收容 6582 個中日韓漢字。表義文字是指文字像是一種圖形符號,只代表語素,而不代表音節,例如中、日、韓、越等文字即屬表義文字。與表義文字相對的是拼音文字,如英語即是拼音文字。
4E00~9FFFh: 中日韓認同表意文字區,總計收容 20902 個中日韓漢字。可到 www.unicode.org 下載各字的編碼。
A000~A4FFh: 彝族文字區,收容中國南方彝族文字和字根。
A500~ABFFh: 包含加拿大土著語、聲調修飾字母、八思巴字、爪哇語、越南傣語等。
AC00~D7FFh: 韓文拼音組合字區,收容以韓文音符拼成的文字。
D800~DFFFh: S 區,專用於 UTF-16
E000~F8FFh: 專用字區,其內容沒有規定,保留供使用者自行添加 ISO 10646 未收容的字元。
F900~FAFFh: 中日韓相容表意文字區,總計收容 302 個中日韓漢字。
FB00~FFFDh: 文字表現形式區,收容組合拉丁文字、希伯來文、阿拉伯文、中日韓直式標點、小符號、半形符號、全形符號等。

輔助字面除了基本多語文字面以外的字面都稱為『輔助字面』,輔助字面多存放罕用的文字。當使用輔助字面的文字時,就得用 4 個位元組來表示一個字了。第一輔助字面 ( Supplementary Multilingual Plane,簡稱 SMP ),擺放拼音文字,主要為現時已不再使用的文字及符號。範圍在 00010000~0001FFDh。

第二輔助字面,又稱為表意文字補充字面 ( Supplementary Ideographic Plane,簡稱 SIP ),整個範圍在 00020000~0002FFFDh。擺放「中日韓統一表意文字擴展 B 區」,共 43253 個漢字,以及中日韓相容表意文字增補 ( CJK Compatibility Ideographs Supplement )。這些文字主要康熙字典、漢語大字典為基礎,扣除已編入 BMP 的文字,再加上各國所提字集,進行整理。其他字面有些是尚未編入文字,有些對我們而言是幾乎不會用到,所以就不介紹了。不過您應當可以參考上面的 UCS-4 全部編碼空間知道尚有許多空間尚未編碼。

UNICODE 轉換成 BIG5在這一章的例子裏,小木偶打算製作一個程式,使其能把 Unicode 轉換成 Big5 碼。還記得 FAT32 裏的 FDB 中,長檔名格式的檔名是以 Unicode 記錄嗎?此章小木偶打算延續第三十四章的內容,針對 DFC.EXE 的缺點改進使其能顯示長檔名。在 Win 9x/Me 的『DOS 視窗』裏的中文是以 Big5 碼顯示中文,因此長檔名必須轉換成 Big5 碼才能正確顯示,否則是一堆亂碼。

轉換表格︰cp950-u2b.txt要撰寫一個可以把 Unicode 轉換成 Big5 的程式,最大的困難在於製作一張上萬個字的萬國碼轉換成大五碼對照表,幸好在網際網路上已經有人製作好了這張表,在 Mozilla Taiwan:Mozilla 系列與 Big5 中文字碼有這樣的一張表。在眾多 Big5 版本裏,小木偶選擇了微軟的 CP950 版本,原因有兩個,一是為了配合底下的例子,DFC3.EXE,DFC3.EXE 是讀取 Win 9x/Me 系統長檔名,眾所皆知,Win 9x/Me 是微軟的產品,自己所改進的 Big5 碼應該會支援吧?;二是該網頁也建議用這一張表。

在該網頁中下載 cp950-u2b.txt 檔案,它就是把萬國碼轉換成 Big5 的表格。cp950-u2b.txt 是純文字檔,底下是前面幾行的內容︰
# big5 unicode 0x0021 0x00A1 0xA246 0x00A2 0xA247 0x00A3 0xA244 0x00A5 0x007C 0x00A6 0xA1B1 0x00A7 0xA14C 0x00A8 0x0063 0x00A9 0x0061 0x00AA 0x002D 0x00AD 0x0052 0x00AE 0xA1C2 0x00AF ……
由上面可以看出,cp950-u2b.txt 是按照第二列的 Unicode 由小至大排列,而 Unicode 前的十六進位數值就是相對應的 Big5 碼,例如第一行的 Unicode 的 0x00A1 換成 Big5 碼就是 0x0021。因此有了這張表,要把 Unicode 轉換成 Big5 就非常容易了,在此特別感謝這張表格的作者。儘管如此,cp950-u2b.txt 對組合語言的設計者來說,還是有兩點不太方便:

cp950-u2b.txt 所有的資料是按照 C/C++ 的十六進位格式製作的表格,並非按照組合語言十六進位格式記錄。
cp950-u2b.txt 檔案裏共收集了 20192 個中文字,每個中文字必須用 Unicode 及 Big5 碼各記錄一次,這兩種編碼都佔用兩個位元組,所以每個中文字佔用 4 個位元組,因此共用去 80768 個位元組,超過一個區段 64KB 的限制。為了解決這個問題,小木偶先撰寫一程式,U2B_2ASM.ASM,這個程式會製造出一個 CP950-U2B_ASM.INC 檔案,這個檔案是一個組合語言包含檔,他把 cp950-u2b.txt 的資料分成兩個區段,big5 與 ucode,big5 區段只存放 Big5 碼資料而 ucode 區段只存放 Unicode 區段。這兩個區段相同偏移位址的資料是對應的,也就是說 big5:0000 位址是 00021h,而 ucode:0000 則是 000a1h。因此 CP950-U2B_ASM.INC 的內容是像這樣的:
big5 segment dw 00021h,0a246h,0a247h,0a244h,0007ch,0a1b1h,0a14ch,00063h dw 00061h,0002dh,00052h,0a1c2h,0a258h,0a1d3h,00032h,00033h ………… dw 0a155h,0a162h,0a1e3h,0a14eh,0a246h,0a247h,0a1c3h,0a244h big5 ends ucode segment dw 000a1h,000a2h,000a3h,000a5h,000a6h,000a7h,000a8h,000a9h dw 000aah,000adh,000aeh,000afh,000b0h,000b1h,000b2h,000b3h ………… dw 0ff5ch,0ff5dh,0ff5eh,0ff64h,0ffe0h,0ffe1h,0ffe3h,0ffe5h ucode ends
當要把 Unicode 轉換成Big5 碼時,只要找出 Unicode 的偏移位址,再切換成 Big5 碼的區段位址,就可取得相對應的 Big5 碼。例如:
;把 AX 內的 UNICDODE 轉換成 BIG-5 ;輸入:AX-UNICDODE ;輸出:NC:轉換成功,此時 AX=BIG-5 ; CY:轉換失敗,此時 AX=『?』 convert_u2big5 proc near uses bx mov bx,ucode mov gs,bx sub bx,bx ;由 ucode:0000 開始搜尋存於 AX 中的 Unicode 位址 next_code: cmp ax,gs:[bx] je find_out add bx,2 or bx,bx ;如果到 BX=0 ( 搜尋完整個 ucode 區段 ) 都還沒找到, jnz next_code ;,表示沒有相對應的 Big5 碼,轉換失敗 stc ;設定進位旗標 mov ax,35a1h ;Big5 的 0a135h=『?』 jmp short u2b_exit find_out: mov ax,big5 mov gs,ax mov ax,gs:[bx] ;取得 Big5 xchg al,ah ;換成 Big-Endian clc ;清除進位旗標 u2b_exit: ret ;返回主程式 convert_u2big5 endp

Big-Endian 與 Little-Endian第三十三章裏提過,FAT32 分割是利用 VFAT 實現長檔名,不管是中文或英文檔名全都採用萬國碼的方式儲存,而非 Big5 碼。例如,上面例子中有一個檔案名為『費玉清-蘆花州.TXT』在目錄磁區裏的儲存方式如下︰
0000 41 BB 8C 89 73 05 6E 0D-FF 06 86 0F 00 0C B1 82 A;..s.n.......1. 0010 1F 82 4C 6B 5E 8A 2E 00-54 00 00 00 58 00 54 00 ..Lk^...T...X.T. 0020 B6 4F A5 C9 B2 4D 7E 31-54 58 54 20 00 0D 38 77 6O%I2M~1TXT ..8w 0030 68 35 68 35 00 00 AB 1B-4A 33 E1 50 1B 03 00 00 h5h5..+.J3aP....
要注意的是用粉紅色標出來的是萬國碼的『費』字,他的代碼是 8CBBH,而其大五碼是 0B64FH,並非 4FB6H。這一點很奇怪,小木偶也不知為什麼要這樣排。一般在 PC 及其相容機種的資料幾乎以 Little-Endian 的方式排列,但在 FDB 中的 Big5 卻是以 Big-Endian 的方式排列。
所謂 Little-Endian 或 Big-Endian 的排列是指數值存放在記憶體的排列方式。當記憶體位址由低位址開始向高位址排好時,先把較小的位數存入的這種方式稱為 Little-Endian,例如上面的 Unicode 的『費』字,其十六進位為『8CBBH』,『BB』分別是個位、十位數,『8C』分別是千位、百位數,所以『BB』填入較低位址而『8C』填入較高位址。因此在傾印時,常常是低位址先印出來,於是變得顛倒了,但是在記憶體裏的排列卻是正常。有關 Little-Endian 或 Big-Endian 可以參考用 C 語言窺探記憶體

DFC3.EXE:檢查檔案所佔磁區是否連續DFC3.EXE 用法與 DFC.EXE 相同,它也只能用在 Win 9x/Me 系列,無法在 Windows NT/2k/XP 裏。其執行結果如下圖︰

為了讓 DFC3.EXE 能夠顯示中文長檔名,修改了 DFC.ASM 裏的 get_filename 副程式,使具有長檔名的檔案能夠呼叫 convert_u2big5 副程式,convert_u2big5 副程式的功用就是把 Unicode 碼轉變成 Big5 碼。

組譯方法因為 DFC3.ASM 原始碼幾乎與 DFC.ASM 一樣,且加上一個轉換 cp950-u2b.txt 變成符合組合語言格式及區段的程式,U2B_2ASM.ASM,所以此處不列出整個內容,請下載 AP10.RAR 後解壓縮。

解壓縮後,在 XP 的命令提示字元或 Win 9x/Me 的 MS-DOS 模式中組譯都可成功。組譯時先把 AP10.RAR 裏所有檔案放於同一子目錄,例如 D:\AP10,再把 cp950-u2b.txt 檔案拷貝到這個子目錄,然後切換到此子目錄,並設定 ML.EXE 的路徑,底下是在 Win XP 系統之下以命令提示字元為例子說明:
D:\AP10>dir [Enter] Volume in drive D is FAT32DATA Volume Serial Number is DC74-CCE3 Directory of D:\AP10 2006/11/21 ?? 10:49 6,499 U2B_2ASM.ASM → AP10.RAR 內的檔案 2006/10/22 ?? 05:37 282,703 CP950-U2B.TXT → 自 Mozilla Taiwan 下載 2006/11/17 ?? 09:44 29,551 DFC3.ASM → AP10.RAR 內的檔案 2006/04/05 ?? 04:49 4,881 MYASMINC.INC → AP10.RAR 內的檔案 4 File(s) 323,634 bytes 2 Dir(s) 1,489,784,832 bytes free D:\AP10>path D:\HomePage\MASM611\BIN;%path% [Enter] D:\AP10>ml /AT U2B_2ASM.ASM [Enter] Microsoft (R) Macro Assembler Version 6.11 Copyright (C) Microsoft Corp 1981-1993. All rights reserved. Assembling: U2B_2ASM.ASM Microsoft (R) Segmented Executable Linker Version 5.31.009 Jul 13 1992 Copyright (C) Microsoft Corp 1984-1992. All rights reserved. Object Modules [.obj]: U2B_2ASM.obj/t Run File [U2B_2ASM.com]: "U2B_2ASM.com" List File [nul.map]: NUL Libraries [.lib]: Definitions File [nul.def]:
在組譯時,須下選項『/AT』,這是為了組譯成 U2B_2ASM.COM 檔,而不是 U2B_2ASM.EXE 檔。接下來就可以利用 U2B_2ASM.COM 把 cp950-u2b.txt 轉換成符合組合語言格式及區段的包含檔,CP950-U2B_ASM.INC 了。
D:\AP10>U2B_2ASM [Enter] D:\AP10>dir [Enter] Volume in drive D is FAT32DATA Volume Serial Number is DC74-CCE3 Directory of D:\AP10 2006/11/21 ?? 10:05 <DIR> . 2006/11/21 ?? 10:05 <DIR> .. 2006/11/21 ?? 10:49 6,499 U2B_2ASM.ASM 2006/10/22 ?? 05:37 282,703 CP950-U2B.TXT 2006/11/17 ?? 09:44 29,551 DFC3.ASM 2006/04/05 ?? 04:49 4,881 MYASMINC.INC 2006/11/21 ?? 10:21 775 u2b_2asm.obj 2006/11/21 ?? 10:21 445 U2B_2ASM.COM 2006/11/21 ?? 10:21 368,566 CP950-U2B_ASM.INC 7 File(s) 693,420 bytes 2 Dir(s) 1,489,408,000 bytes free
接下來組譯 DFC3.ASM:
D:\AP10>>ml dfc3.asm [Enter] Microsoft (R) Macro Assembler Version 6.11 Copyright (C) Microsoft Corp 1981-1993. All rights reserved. Assembling: dfc3.asm Microsoft (R) Segmented Executable Linker Version 5.31.009 Jul 13 1992 Copyright (C) Microsoft Corp 1984-1992. All rights reserved. Object Modules [.obj]: dfc3.obj Run File [dfc3.exe]: "dfc3.exe" List File [nul.map]: NUL Libraries [.lib]: Definitions File [nul.def]:
如此就得到 DFC3.EXE,檔案僅 84368 個位元組。不過 DFC3.EXE 只能在 Win 9x/Me 系統中執行,在 Win NT/2k/XP 中無法執行。
註一:在 DOS 系統裏,每個字在螢幕上顯示的寬度都是相同的,但載入倚天中文後,中文字不僅佔用兩個位元組,在螢幕顯示時的寬度也是英文字的兩倍,故稱全形字,而原來的英文自稱為半形字體。不過,在 Big5 碼裏,也有全形字體的英文字母,在 A2CF~A343,同樣的,阿拉伯數字、希臘字母也都有全形字體。
註二:

UTF-16 與 UTF-8UCS-4 字集雖然能容納古今中外全球人類所書寫過的文字及符號,但是其實有九成五以上的文字及符號都編入 UCS-2 字集 ( 即 BMP )。很明顯的 UCS-2 要比 UCS-4 有效率得多,不說別的,單只比較儲存空間,UCS-2 就只有 UCS-4 的一半。設想如果一篇數千字或數萬字的文件裏,就只有十幾個字在 BMP 以外的字面,若只為了這幾個字就得採用 UCS-4 字集,顯然是很不符合經濟效率。因此 ISO 10646 特別規定在 BMP 以外的字可以轉換成兩個或多個 16 位元的 UCS-2 表示,這種表示或轉換方式稱為 UCS-16,即 UCS Transformation Format 之縮寫。
現在已經被使用的字面,只有第 00 群組前十四個字面用到,因此只需考慮第 00 群組的第 00 字面到第 0E 字面即可。其轉換方式是把 32 位元的 UCS-4 的第 10 個位元到第 15 個位元變成轉換後第一個字組的低 6 位元,UCS-4 的第 16 個位元到第 19 個位元所組成的二進位數減 1,變成轉換後第一個字組的第 6 到第 9 位元,而轉換後的最高 6 位元則固定是 110110;UCS-4 的第 0 位元到第 9 位元變成第二個字組的低 10 位元,高 6 位元固定是 110111。因此 UCS-4 經過 UTF-16 轉換後的高位元組落在 D800~DBFF 之間,低位元組則落在 DC00~DFFF 之間。如下圖:

現在網路傳輸的資料仍大多以 ASCII 編碼的方式傳輸。也就是說,在網路設備如路由器等會去檢查傳輸的資料是否包含 C0 等 ASCII 控制字元,如果有的話,會依狀況處理。因此不管是 UCS-2 或 UCS-4 字元在網路傳輸時,只要含有 C0 控制字元都會被誤認。為了讓 UCS-2 或 UCS-4 字元能安然通過網路設備的檢查,於是 ISO 10646 也規定了 UTF-8 轉換方式。
UTF-8 轉換規則很簡單,如果 USC-4 字元是等於 7F 或小於 7F 以下,則不轉換直接取最低八位元傳送。如果超過 7F 時,則轉換成數個位元組,第一個位元組前面有幾個 1,就代表轉換成幾個位元組,之後接上一個 0,然後從原來的 UCS-4 開始逐一把位元由高而低填上,直到滿了 8 個位元,轉換後的第二個位元組以後前兩個位元必是 10,然後其餘的 6 個位元就是剩餘的 UCS-4 位元依次填上。方法如下:

原來的 UCS-4
字元範圍 位元結構 經 UTF-8 轉換後
00000000

0000007F 第一個字組:
第二個字組: 第一個位元組:
00000080

000007FF 第一個字組:
第二個字組: 第一個位元組:
第二個位元組:
00000800

0000FFFF 第一個字組:
第二個字組: 第一個位元組:
第二個位元組:
第三個位元組:
00010000

001FFFFF 第一個字組:
第二個字組: 第一個位元組:
第二個位元組:
第三個位元組:
第四個位元組:
上表說明 UCS-4 轉換後的結果,如果是 UCS-2 的話,就不考慮第一個字組,結果一樣。例如『中』的萬國碼是 4E2D,轉換成二進位是:
0100 1110 0010 1101
4E2D 在 0800 與 FFFF 之間,因此會轉換成 3 個位元組,轉換如下:
第一個位元組:1110 0100 →E4 第二個位元組:1011 1000 →B8 第三個位元組:1010 1101 →AD
第一個位元組的黃色部份有 3 個一,表示 UTF-8 轉換後有三個位元組,其後所接黃色的零表示分隔記號;第二、三最前面黃色的『10』也表示 UTF-8 轉換後的記號。而中的萬國碼的前四個位元是紅色的『0100』就接在 UTF-8 轉換後的第一個位元組後四個位元;而藍色的『1110 00』也就接在第二個位元組之後的 6 個位元;UCS-2 最後的 6 個位元組,就接在第三個位元組的最後 6 個位元。
在 Win XP 的記事本裏,要儲存檔案時,會出現一個『另存新檔』的對話盒,其中『編碼:』複合框就是可以選擇以不同的四種編碼方式存入檔案。如下圖:

其中,ANSI 編碼指的就是以 ASCII 或 Big5 碼方式存入。例如在記事本中有一句『我學Assembly。』字,存檔時,存入的是 ASCII 與 Big5 碼 ( 英文半形字用 ASCII 碼,中文或全形字用 Big5 碼 ),內容如下:
A7 DA BE C7 41 73 73 65 6D 62 6c 79 A1 43
您可以自行到前面提到的地方查『我』、『學』這兩字的 Big5 碼和到附錄四查這些英文字的 ASCII 碼是否符合上面的十六進位數。如果用 Unicode 方式存,則會以 UCS-2 Little-Endian 方式存入,所存入內容為
FF FE 11 62 78 5B 41 00 73 00 73 00 65 00 6D 00 62 00 6C 00 79 00 02 30
最前面兩個位元組是 FF FE,這兩位元組的目的是用來分辨 Big-Endian 還是 Little-Endian。在萬國碼裏,FEFF 是無寬度不中斷空格 ( zero width no-break space ),其 Little-Endian 是 FF FE,而 FFFE 在萬國碼沒有編碼,因此萬國碼是不會出現 FFFE 這種碼的,萬一出現,那就表示是 Little-Endian 編碼。所以 UCS 中建議我們在傳送或儲存萬國碼時,最先傳送、儲存 FEFF 字元,表示 Big-Endian,或者傳送、儲存 FFFE 表示 Little-Endian。而 FEFF 字元經 UTF-8 轉換後變成 EF BB BF,所以前三個位元組是 EF BB BF 的就是 UTF-8 編碼。
接下來的十六進位數,6211、5B78、0041…等分別是『我學A…』的萬國碼,以 UCS-2 Little-Endian 編碼。
如果以 Big-Endian 方式存入時,也是以 UCS-2 編碼方式編碼,但是以大數在前方式排列,因此您會看見與 Unicode 方式存檔時兩兩一組且前後互換,所存內容為
FE FF 62 11 5B 78 00 41 00 73 00 73 00 65 00 6D 00 62 00 6C 00 79 30 02
如果以 UTF-8 方式存檔時,內容就變成:
EF BB BF E6 88 91 E5 AD B8 41 73 73 65 6D 62 6C 79 E3 80 82
您可自行驗證。

沒有留言:

張貼留言