正确理解各种编码问题

转载 2007年10月09日 09:51:00
如果你开发过的软件项目中涉及到多语言支持的问题,那么相信你没少碰到过乱码问题,然后在寻求解决问题的途径过程中被一些概念如ASCII, ISO-8859-1, Unicode,UTF-8,GBK,GB2312等等所困扰。本文有助于你正确的理解这些概念。
1. ASCII
用7位编码将英文字符和一些常用的符号存诸为从0到127的数值。
 
2. ISO-8859-1
法语、西班牙语和德语之类的西欧语言都使用叫做ISO-8859-1的编码系统(也叫做“latin-1”)。它使用7位ASCII字符表示从0到127的字符,但接着扩展到了128-255的范围来表示如n上带有一个波浪线(241),和u上带有两个点(252)的字符等等。可以说ASCII是ISO-8859-1的子集。
 
3. Unicode
    Unicode用一个2字节数字表示每个字符,从0到65535。每个 2 字节数字表示至少在一种世界语言中使用的一个唯一字符。(在多种语言中都使用的字符具有相同的数字码。)这样就确保每个字符一个数字,并且每个数字一个字符。Unicode数据永远不会模棱两可。Unicode使用相同的数字表示ASCII和ISO-8859-1中的字符。只是这两种编码用一个字节表示,而Unicode用两个字节表示。所以Unicode表示这两种编码的字符时只要用低字节就可以了,高字节为0。
 
4. UTF-8
    UTF-8是一种变长的编码方式,每个UTF-8的编码可以是1至6个字节长。它将Unicode编码的字符采用变长的方式进行编码。对Unicode中属于ISO-8859-1的编码采用和ISO-8859-1相同的单字节编码。其他字符采用两字节以上的编码。实际上对于两个字节的Unicode编码,UTF-8只要三个字节即可表示。第一个字节由n个1(1< n <= 6)开始, n表示编码的字节数,后面每个字节都以10开始,后面6位为有效位。将第一位的剩余位和后面的所有字节的后六位连接起来就是对应的Unicode编码的数值。例如汉字“中”的编码:
 
Unicode:           4E      2D
01001110 00101101
 
UTF-8:              E4      B8     AD
11100100 10111000 10101101
 
可以通过以下方式进行证实:
       用记事本创建一个文本文件,输入汉字“中”分别保存为Unicode格式和UTF-8格式。 将UltraEdit的自动识别UTF-8文件格式选项禁止,然后用其打开这两个文件,选用二进制查看方式,可以看到:
    UTF-8格式文件编码为“EF BB BF E4 B8 AD”。其中有个三字节的前缀“EF BB BF”,这是UTF-8格式文本文件的标识。不过这个前缀不要,某些文本查看软件也可以通过编码判断出UTF-8格式。“E4 B8 AD”就是“中”的UTF-8编码。
    Unicode格式的文件的完整编码是“FF FE 2D 4E”。前面有个双字节前缀“FF FE”,这是Unicode格式文本文档的编码标识。而我们看到的编码是“2D 4E”,而不是如我前面所说的“4E 2D”,为什么呢?因为数字是按照低字节在先高字节在后的顺序存储的,所以实际的Unicode编码恰恰是“4E2D”。
 
5. GB2312和GBK
       这两种编码都是汉字的编码标准,其中前者是后者的子集。GBK编码的文本文档中对于ASCII中的字符用相同的单字节表示;对于汉字和汉语中的标点符号等采用双字节编码,其中高字节大于0x80,而ASCII的所有字符的编码均小于0x80, 所以ASCII和GBK的字符是可以混和起来的。GBK的字符集和Unicode进行转换是无规则的,需要转换表才能进行转换。
 
6.下面给出我用Java语言写的Unicode和UTF-8转换的程序片段,供大家参考。
 
因为Java语言的字符使用Unicode编码的,所以程序中是对UTF-8编码的字符串的字节数组和Java的String类型进行转换。String对象中的每一个Character就是一个Unicode编码的字符。
 
public String utf8Bytes2String(byte[] buff){
              if(buff == null)
                     return null;
             
              StringBuffer sb = new StringBuffer();
             
              int idx = 0;
             
              if(buff[0] == (byte)0xEF &&
                            buff[1] == (byte)0xBB &&
                            buff[2] == (byte)0xBF)
                     idx = 3;//Skip UTF8 header
 
              while(idx < buff.length){
                     int hB = buff[idx] & 0xFF;
                     int bCnt = 0;
                     int check = 0x80;
                     for(int i=0; i<8; i++){
                            if((hB & check) != 0){
                                   bCnt ++;
                                   check >>= 1;
                            }else
                                   break;
                     }
                    
                     if(bCnt <= 1){
                            char c = 0;
                            c |= buff[idx] & 0xFF;
                            sb.append(c);
                            idx++;
                     }else if(bCnt == 2){
                            char c = 0;
                            c |= buff[idx] & 0x03;
                            c <<= 6;
                            if((buff[idx+1] & 0xC0) != 0x80)
                                   return null;
                            c |= buff[idx+1] & 0x3F;
                            idx += 2;
                            sb.append(c);
                     }else if(bCnt == 3){
                            char c = 0;
                            c |= buff[idx] & 0x0F;
                            c <<= 6;
                            if((buff[idx+1] & 0xC0) != 0x80)
                                   return null;
                            c |= buff[idx+1] & 0x3F;
                            c <<= 6;
                            if((buff[idx+2] & 0xC0) != 0x80)
                                   return null;
                            c |= buff[idx+2] & 0x3F;
                            idx += 3;
                            sb.append(c);
                     }else
                            return null;
              }
             
              return sb.toString();
       }
      
       public byte[] string2Utf8Bytes(String str){
              if(str == null)
                     return null;
             
              ByteArrayOutputStream bos = new ByteArrayOutputStream();
              try {
                     string2Utf8Stream(str, bos);
              } catch (IOException e) {
                     e.printStackTrace();
              }
              return bos.toByteArray();
       }
 
public void string2Utf8Stream(String str, OutputStream os) throws IOException {
              if(str == null || os == null)
                     return;
             
              for(int i=0; i<str.length(); i++){
                     char c = str.charAt(i);
                     if(c < 0x80){
                            os.write((byte)c);
                     }else if(c >=0x80 && c < 0x100){
                            int hi = c >> 6;
                            hi |= 0xC0;
                            int lo = c & 0x3F;
                            lo |= 0x80;
                            os.write(hi);
                            os.write(lo);
                     }else{
                            int first = c >> 12;
                            first |= 0xE0;
                            int second = c >> 6;
                            second &= 0x3F;
                            second |= 0x80;
                            int third = c & 0x3F;
                            third |= 0x80;
                            os.write(first);
                            os.write(second);
                            os.write(third);
                     }
              }
       }
 
  参考:由一节废电池引起 

实例详细介绍各种字符集编码转换问题

http://blog.csdn.net/dracularking/article/details/2257468 本文背景: 本人在编程时需要匹配字符串,由此想到了如果文件是各种字符编码的话...
  • bytxl
  • bytxl
  • 2014年01月08日 16:49
  • 1540

【高级算法】Lasvegas+回溯算法解决3SAT问题(C++实现)

1.SAT问题描述命题逻辑中合取范式 (CNF) 的可满足性问题 (SAT)是当代理论计算机科学的核心问题, 是一典型的NP 完全问题.在定义可满足性问题SAT之前,先引进一些逻辑符号。 一个...
  • zhoubin1992
  • zhoubin1992
  • 2015年06月15日 21:04
  • 1377

人工智能:第三章 搜索推理技术

第三章 搜索推理技术 教学内容:本章在上一章知识表示的基础上研究问题求解的方法,是人工智能研究的又一核心问题。内容包括早期搜索推理技术,如图搜索策略和消解原理;以及高级搜索推理技术,如规则演绎...
  • GarfieldEr007
  • GarfieldEr007
  • 2015年12月07日 19:48
  • 1380

正确理解和使用GBK及UTF-8编码

网页编码英文译为web page encoding,是在网页中指定其特定的字符编码格式的库。 GBK是国家标准GB2312基础上扩容后兼容GB2312的标准。GBK的文字编码是用双字节来表示的,...
  • u013161278
  • u013161278
  • 2014年12月05日 20:08
  • 254

正确理解和使用GBK及UTF-8编码

 网页编码英文译为web page encoding,是在网页中指定其特定的字符编码格式的库。 GBK是国家标准GB2312基础上扩容后兼容GB2312的标准。GBK的文字编码是用双字节来表示...
  • huchunlinnk
  • huchunlinnk
  • 2014年09月03日 15:23
  • 472

正确理解UNICODE UTF-8等编码方式

如果你开发过的软件项目中涉及到多语言支持的问题,那么相信你没少碰到过乱码问题,然后在寻求解决问题的途径过程中被一些概念如ASCII, ISO-8859-1, Unicode,UTF-8,GBK,GB2...
  • dyzok88
  • dyzok88
  • 2014年12月22日 17:20
  • 1288

浏览器正确理解和使用GBK及UTF-8(UTF-8 + BOM)网页编码

如何让浏览器正确识别网页编码?一般在网页中都要有如下一句:,指示此网页的字符集编码是GB2312。(或者UTF-8) 页面有时候指定了编码为什么有时会出现乱码?这可能是页面申明编码与文件本身编码不一...
  • txl16211
  • txl16211
  • 2014年10月26日 20:23
  • 1465

正确理解Threadlocal类以及内存泄漏问题

2017.8.5更新:tomcat低版本在reload或者stop一个web app时(一个tomcat可以运行多个web app),如果tomcat线程池中的线程中的threadlocalmap持有...
  • joenqc
  • joenqc
  • 2017年03月12日 21:59
  • 271

正确理解Linux内存占用过高的问题

几个关于显看内存的命令: top 之后可以按大写M(按内存占用排序)P(按CPU占用排序) free -m -s2 每隔2秒按兆字节显示内存使用情况 最近有个月经问题,老有人问为何开机后,还...
  • iloli
  • iloli
  • 2011年09月10日 12:06
  • 738

递归思维的正确理解&&递归思维在处理问题中的运用

初学者在学习递归的时候,总是很容易陷入对递归过程的纠缠,总想弄清递归到底是怎么运作的,认为这是学习递归的方法之一。其实也不奇怪,初学者接触递归大多都是在学习面向过程语言的时候,比如说C语言,但事实上,...
  • weixin_41133154
  • weixin_41133154
  • 2018年01月03日 13:33
  • 15
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:正确理解各种编码问题
举报原因:
原因补充:

(最多只允许输入30个字)