天天看點

字元編碼(1)——Unicode,utf-8

字元編碼

編碼是一個将一組Unicode字元轉換業個位元組序列的過程。而解碼是将一個編碼位元組序列轉換為一組Unicode字元的過程。

Unicode字元是什麼?

Unicode字元集可以簡寫為UCS,也就是Unicode charactor set

Unicode編碼是國際組織制定的可以容納世界上所有文字和符号的字元編碼方案。它通過0到0x10FFFF來映射字元,最多可容納1114112個字元(16進制的10FFFF的值是1114111,然後加一個0x000000就是1114112個)。可以看一下1114112的二進制表示形式為:1 0001 00000000 00000000

UTF是什麼?

UTF是Unicode轉換格式的意思,是UCS Transformation Format的縮寫。

Utf-8

UTF-8以位元組為機關對Unicode進行編碼。utf-8特點是對不同範圍的字元用不同長度的編碼。從Unicode到UTF-8的編碼方式如下:

Unicode編碼(16進制) ║ UTF-8 位元組流(二進制)

000000 - 00007F ║ 0xxxxxxx

000080 - 0007FF ║ 110xxxxx 10xxxxxx

000800 - 00FFFF ║ 1110xxxx 10xxxxxx 10xxxxxx

010000 - 10FFFF ║ 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

例如:“趙”這個字的Unicode編碼(16進制表示方法)是:8d 75

這個編碼在.net中可以通過ToString()方法來實作。為了進行後邊的說明。這裡先給出測試用的轉換方法: 

public static class CharSetHelper

{

    public static string TransCoding(this int iValue,eTrans eType)

    {

        return Convert.ToString(iValue, (int)eType);

    }

    public static string GetCorrectCoding(this string selfChar, Encoding encoding, eTrans eType)

        int iUnicode = (int)char.Parse(selfChar);

        return iUnicode.TransCoding(eType);

}

public enum eTrans

Binary=2,

Octonary=8,

Decimal=10,

Hexadecimal=16

一個枚舉,用于枚舉數的進制,一個從字串轉換到特定的字元編碼,并以指定進制表示的方法。

·另外,可以再把系統的電腦調出來,改為科學型。

·準備可以檢視進制的編輯器,我用的是ultra。

另外說明一下:char.Parse方法:它将指定字元串的值轉換為它的等效 Unicode 字元

百家姓趙錢孫李中的“趙”字,這裡是簡體趙字。可以查一下它的Unicode編碼,并用10進制和16進制表示:

string cc="趙";

UnicodeEncoding _unicode = new UnicodeEncoding();

string s1 = cc.GetCorrectCoding(_unicode, eTrans. Decimal);

string s2 = cc.GetCorrectCoding(_unicode, eTrans.Hexadecimal);

10進制:36213

16進制:8d75

然後建立立記事本。寫一個“趙”字,儲存,儲存時編碼選擇unicode。然後用ultra打開。切換到16進制編輯模式。可以看到:FF FE 75 8D

還有一個要說的就是這裡的10進制是8D75的10進制表示法,同時也是Unicode編碼表中漢字“趙”的編号。

其中8D 75是“趙”字的16進制編碼。而多出來的FE FF就是位元組序,byte order mark(BOM),用來判斷位元組流的位元組序。在傳輸位元組流前,先傳輸被作為BOM的字元。

下邊是utf的BOM:

UTF-8 ║ EF BB BF

UTF-16LE ║ FF FE

UTF-16BE ║ FE FF

UTF-32LE ║ FF FE 00 00

UTF-32BE ║ 00 00 FE FF

這個位元組序不要出現在傳輸中,例如:在進行組包發送資料時,當字元使用utf-8編碼時,會多出BOM,是以要先截除BOM,然後進行傳輸,這點是要注意的。對于utf-8編碼的字元,要向前截除3個位元組。

下面再看一下UTF-8編碼的16進制。還是“趙”字。在記事本中添加“趙”字,編碼選擇utf-8,然後在ultra中打開,切換到16進制模式,之前,先看一下這個字在程式中的utf-8編碼下的16進制情況:

16進制:E8B5B5

現在提供一下編碼的16進制檢視方法:

public static string GetRightEncodingString(this string selfChar,Encoding encoding, eTrans eType)

    byte[] bb = encoding.GetBytes(selfChar);

    bb=bb.Reverse().ToArray();

    string strTemp = string.Empty; 

    foreach (byte b1 in bb)

        strTemp += Convert.ToInt32(b1.ToString()).TransCoding(eType);

    return strTemp;

這個方法是連着上邊的進行的。

在utf-8下的的記事本上,“趙”字的全16進制格式是:EF BB BF E8 B5 B5

其中後3個位元組是“趙”字的utf8編碼,而前三個位元組就是BOM了。

再來看一下,utf-8的編碼格式:

在0-7F之間用的一個位元組。與Ascii碼對應。7F就是10進制的127。

在128-2047之間用2個位元組。

在2048-65535之間用3個位元組。

在65536-1114111之間用4個位元組

而unicode與utf-8之間的轉換怎麼樣的?還以上表為例子,例如:“趙”字,

它的16進制unicode編碼是:8D75,它在第三行也就是2048-65535之間。

然後,8D75的二進制表示為(用電腦轉一下):1000110101110101

然後,用這些二進制從低位向高位(從右向械)依次取6位:

1000-110101-110101

然後替換x,如果不夠位數,則高位用0補,然後得到的二進制是:

11101000-10110101-10110101

然後,這3個位元組的16進制就是:E8 B5 B5

然後再以字母M來試一下,因為這個字母是Ascii碼表中的值(這樣說不太準确),或者說它是127之内的值,是以utf-8編碼格式與ascii一樣。(盡管如此,做為utf-8編碼,文本串最前邊還是多出3個位元組,BOM)

現在再找一個字:“李”,它的unicode編碼值是: 674E

它的範圍在:000800 - 00FFFF ║ 1110xxxx 10xxxxxx 10xxxxxx

這個範圍内,然後,這2個位元組的二進制是:110011101001110,然後由低位向高位按6位取:

110-011101-001110,不足4位的高位用0補:0110-011101-001110,然後替換x就是:

11100110-10011101-10001110,16進制數是:E69D8E

在ultra中可以驗證一下:utf-8全文:EF BB BF E6 9D 8E

現在通過程式來實作一下Unicode到utf-8的轉換(通過移位來進行)

準備工作:參照:1110xxxx 10xxxxxx 10xxxxxx 其中的X用0替換,表示為:

11100000 10000000 10000000

然後,一個unicode編碼的字元是2個位元組,就是16位,而utf-8編碼(這裡還以漢字為例)是3個位元組

UnicodeEncoding _unicoding=new UnicodeEncoding();

string str="趙";

int k = int.Parse(str.GetUnicode(new UnicodeEncoding(), eTrans.Decimal));

byte[] bb = _unicoding.GetBytes(str);

先得到“趙”字的unicode值和位元組。

這三個位元組,會16進制表示為:0xE0,0x80,0x80

這個字的unicode的編碼的二進制表示為:1000-110101-110101

先算第一個位元組:

第一個位元組為0xE0與上1000(二進制),而1000可以是“趙”字的unicode編碼右移12位,是以:

int k1 = k >> 12;

_list.Add(0xe0|k1);

第二個位元組是0x80與上110101,

而110101是“趙”字的unicode編碼右移6位,變為:1000-110101,然後與上111111就可以了,而111111的16進制為:0x3F,是以:

int k2 = k >> 6  &0x3F;

_list.Add(0x80 | k2);

第三個位元組是0x80與上110101,

110101是“趙”字的unicode的後6位,是以與上6個1就可以了,是以:

int k3 = k & 0x3F;

_list.Add(0x80 | k3);

結果是:

232|181|181

E8|B5|B5

部落格園大道至簡

<a href="http://www.cnblogs.com/jams742003/" target="_blank">http://www.cnblogs.com/jams742003/</a>

轉載請注明:部落格園

繼續閱讀