字符编码

编码是一个将一组Unicode字符转换业个字节序列的过程。而解码是将一个编码字节序列转换为一组Unicode字符的过程。

 

Unicode字符是什么?

Unicode字符集可以简写为UCS,也就是Unicode charactor set

Unicode编码是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。它通过00x10FFFF来映射字符,最多可容纳1114112个字符(16进制的10FFFF的值是1114111,然后加一个0x000000就是1114112个)。可以看一下1114112的二进制表示形式为:1 0001 00000000 00000000

 

UTF是什么?

UTFUnicode转换格式的意思,是UCS Transformation Format的缩写。

 

Utf-8

UTF-8以字节为单位对Unicode进行编码。utf-8特点是对不同范围的字符用不同长度的编码。从UnicodeUTF-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进制是8D7510进制表示法,同时也是Unicode编码表中汉字的编号。

 

其中8D 75字的16进制编码。而多出来的FE FF就是字节序,byte order markBOM),用来判断字节流的字节序。在传输字节流前,先传输被作为BOM的字符。

下边是utfBOM

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的编码格式:

000000 - 00007F  0xxxxxxx

000080 - 0007FF  110xxxxx 10xxxxxx

000800 - 00FFFF  1110xxxx 10xxxxxx 10xxxxxx

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

07F之间用的一个字节。与Ascii码对应。7F就是10进制的127

1282047之间用2个字节。

204865535之间用3个字节。

655361114111之间用4个字节

 

unicodeutf-8之间的转换怎么样的?还以上表为例子,例如:字,

它的16进制unicode编码是:8D75,它在第三行也就是204865535之间。

000800 - 00FFFF  1110xxxx 10xxxxxx 10xxxxxx

然后,8D75的二进制表示为(用计算器转一下):1000110101110101

然后,用这些二进制从低位向高位(从右向械)依次取6位:

1000110101110101

然后替换x,如果不够位数,则高位用0补,然后得到的二进制是:

111010001011010110110101

然后,这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位取:

110011101001110,不足4位的高位用0补:0110011101001110,然后替换x就是:

11100110100111011000111016进制数是:E69D8E

ultra中可以验证一下:utf-8全文:EF BB BF E6 9D 8E

 

现在通过程序来实现一下Unicodeutf-8的转换(通过移位来进行)

准备工作:参照:1110xxxx 10xxxxxx 10xxxxxx 其中的X0替换,表示为:

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值和字节。

 

11100000 10000000 10000000

这三个字节,会16进制表示为:0xE00x800x80

这个字的unicode的编码的二进制表示为:1000110101110101

先算第一个字节:

第一个字节为0xE0与上1000(二进制),而1000可以是字的unicode编码右移12位,所以:

int k1 = k >> 12;
_list.Add(
0xe0|k1);

 

第二个字节是0x80与上110101

110101字的unicode编码右移6位,变为:1000110101,然后与上111111就可以了,而11111116进制为:0x3F,所以:

int k2 = k >> 6  &0x3F;
_list.Add(
0x80 | k2);

 

第三个字节是0x80与上110101

110101字的unicode的后6位,所以与上61就可以了,所以:

int k3 = k & 0x3F;
_list.Add(
0x80 | k3);

 

结果是:

232181181

E8B5B5

 

posted on 2010-03-25 16:42  梅桦  阅读(3689)  评论(0编辑  收藏  举报