字符编码笔记

来源:互联网 发布:碧螺春 淘宝上哪个正宗 编辑:程序博客网 时间:2024/05/17 03:27

Author: Zibin Zheng

http://www.cse.cuhk.edu.hk/~zbzheng



字符编码集按长度分为 SBCS(单字节字符集),DBCS(双字节字符集)两大类

big endian和littleendian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,还是将49写在前面?如果将6C写在前面,就是big endian。还是将49写在前面,就是little endian。

关于中文编码

早期的计算机使用7位的ASCII编码,为了处理汉字,程序员设计了用于简体中文的GB2312和用于繁体中文的big5。

ASCII —→ GB2312 —–> GBK —–> GB18030

GB2312(1980年)一共收录了7445个字符,它支持的汉字太少了。

1995年的汉字扩展规范GBK1.0收录了21886个符号

2000年的GB18030是取代GBK1.0的正式国家标准。该标准收录了27484个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字。现在的PC平台必须支持GB18030,对嵌入式产品暂不作要求。所以手机、MP3一般只支持GB2312。

GB2312、GBK到GB18030都属于双字节字符集 (DBCS)。

从ASCII、GB2312、GBK到GB18030,这些编码方法是向下兼容的

关于unicode

每个国家(或区域)都规定了计算机信息交换用的字符编码集,如美国的扩展 ASCII码, 中国的 GB2312-80,日本的 JIS等,作为该国家/区域内信息处理的基础。早期的软件(尤其是操作系统),为了解决本地字符信息的计算机处理,出现了各种本地化版本,为了区分,引进了LANG, Codepage等概念。但是由于各个本地字符集代码范围重叠,相互间信息交换困难;软件各个本地化版本独立维护成本较高。因此有必要将本地化工作中的共性抽取出来,作一致处理,将特别的本地化处理内容降低到最少。这就导致了几乎包含了所有字形的 Unicode的出现。

Unicode的最初目标,是用1个16位的编码来为超过65000字符提供映射。但这还不够,它不能覆盖全部历史上的文字,也不能解决传输的问题(implantation head-ache's)。

因此,Unicode用一些基本的保留字符制定了三套编码方式。它们分别是UTF-8,UTF-16和UTF-32。正如名字所示,在UTF-8中,字符是以8位序列来编码的,用一个或几个字节来表示一个字符。这种方式的最大好处,是UTF-8保留了ASCII字符的编码做为它的一部分,例如,在UTF-8和ASCII中,“A”的编码都是0×41.

UTF-16和UTF-32分别是Unicode的16位和32位编码方式。考虑到最初的目的,通常说的Unicode就是指UTF-16。在讨论Unicode时,搞清楚哪种编码方式非常重要。Unicdoe相关的技术介绍参见http://www.unicode.org/unicode/standard/principles.html.

而Unicode只与ASCII兼容,与GB码不兼容。例如“汉”字的Unicode编码是6C49,而GB码是BABA。

CJK就是中日韩的意思,Unicode为了节省码位,将中日韩三国语言中的文字统一编码。

UTF-8的编码是变长的 1-4字节

对于一些汉字占绝大多数的文档,直接用UCS-2格式保存,比用UTF-8格式保存后的存储体积更小一些,因为在UTF-8中汉字往往需要占用3个byte的空间。而当英文字母占大多数时,用UTF-8则可以使文件体积小很多(大家可以用记事本中这两种不同的“另存为”方式来验证一下)。由于世界传输的文档还是以英文为主流,所以这种编码被理所当然地认为从总体上减小了文件的体积。

UCS规定了怎么用多个字节表示各种文字。怎样传输这些编码,是由UTF(UCS Transformation Format)规范规定的,常见的UTF规范包括UTF-8、UTF-7、UTF-16。 UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下: UCS-2编码(16进制) UTF-8 字节流(二进制)

0000 –007F 
0xxxxxxx
0080 - 07FF
110xxxxx 10xxxxxx
0800 - FFFF
1110xxxx 10xxxxxx 10xxxxxx

例如“汉”字的Unicode编码是6C49。6C49在0800-FFFF之间,所以肯定要用3字节模板了:1110xxxx 10xxxxxx10xxxxxx。将6C49写成二进制是:0110 110001 001001,用这个比特流依次代替模板中的x,得到:1110011010110001 10001001,即E6 B1 89。

Unicode、Unicode big endian和UTF-8编码的txt文件的开头会多出几个字节,分别是FF、FE(Unicode),FE、FF(Unicode big endian),EF、BB、BF(UTF-8)。 这些多出来的字节是为了方便识别是哪一种编码,

FE FF -> 1111 1110 1111 1111 –> 1111 111011 111111

加上上面表格的模板可得:11101111 10111011 10111111 –> EF BB BF 可以看出来UTF8的开头的标示其他也是按照unicode的标示进行对应的编码而得到的。

参考文章:

关于编码、unicode、utf-8的讨论
http://bbs.netton.cn/ShowPost.asp?ThreadID=1906

内码,unicode,UTF等术语浅析
http://matchchen.blogchina.com/matchchen/1849189.html 趣谈Unicode编码[转载
http://www.bloghome.cn/posts/4006

writeUTF:

 
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeUTF("中文中");
0:0
1:9
2:ffffffe4
3:ffffffb8
4:ffffffad
5:ffffffe6
6:ffffff96
7:ffffff87
8:ffffffe4
9:ffffffb8
10:ffffffad

可以知道,writeUTF和readUTF之间的对应是通过0和1的byte来知道读多长的字符串。他们是一对的,要一起配套使用!!!

Word中的内容是用unicode编码的格式进行编码的,并不是UTF8,在将unicode变成string的过程中要注意几个事情:

1. 将前后的两个byte对调 2. 将unicode头忽略掉,不然会显示不正常
public void unicodeToString(byte[] unicode) { 
StringBuffer stringbuffer = new StringBuffer("");
for (int j = 0; j < unicode.length;)
{
int k = unicode[j++];
int l = unicode[j++];

//把高位和低位数组装起来
char c = (char) ((k & 0xff)+ ((l << 8) & 0xff00));
System.out.println("-----"+Integer.toHexString((k & 0xff)+ ((l << 8) & 0xff00)));
// 忽略前1,2个byte,它是unicode的头,如果加上会造成显示不正常。
if(j==2)
continue;
stringbuffer.append(c);
}
System.out.println(stringbuffer.toString());
}

private byte[] unicodeToUTF8(byte[] unicode) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
for (int j = 0; j < unicode.length;)
{
int k = unicode[j++];
int l = unicode[j++];
// 注意要& 0xff,不然会出错误
int c = (int) (k & 0xff)+ ((l << 8) & 0xff00);

//忽略前1,2个byte, unicode的头
if(j==2)
continue;

if(c <= 0x007F){
bos.write((byte)c);
}else if(c <= 0x07ff){
bos.write((byte) ((c >> 7) | 0xc0));
bos.write((byte) ((c & 0x3f) | 0x80));
}else {
bos.write((byte) ((c >> 12) | 0xe0));
bos.write((byte) (((c >> 6) & 0x3f) | 0x80));
bos.write((byte) ((c & 0x3f) | 0x80));
}
}

return bos.toByteArray();
}

获得UTF的byte数组后,可以用它new一个新的UTF的string。

 
原创粉丝点击