字符编码(1)——Unicode,utf-8

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

字符编码(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的编码格式:
000000 - 00007F ║ 0xxxxxxx
000080 - 0007FF ║ 110xxxxx 10xxxxxx
000800 - 00FFFF ║ 1110xxxx 10xxxxxx 10xxxxxx
010000 - 10FFFF ║ 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
在0-7F之间⽤的⼀个字节。

与Ascii码对应。

7F就是10进制的127。

在128-2047之间⽤2个字节。

在2048-65535之间⽤3个字节。

在65536-1114111之间⽤4个字节
⽽unicode与utf-8之间的转换怎么样的?还以上表为例⼦,例如:“赵”字,
它的16进制unicode编码是:8D75,它在第三⾏也就是2048-65535之间。

000800 - 00FFFF ║ 1110xxxx 10xxxxxx 10xxxxxx
然后,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个字节的⼆进制是:110011*********,然后由低位向⾼位按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值和字节。

11100000 10000000 10000000
这三个字节,会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。

相关文档
最新文档