zoukankan      html  css  js  c++  java
  • 正确理解UNICODE UTF8等编码方式

    如果你开发过的软件项目中涉及到多语言支持的问题,那么相信你没少碰到过乱码问题,然后在寻求解决问题的途径过程中被一些概念如ASCII, ISO-8859-1, UnicodeUTF-8GBKGB2312等等所困扰。本文有助于你正确的理解这些概念。

    1. ASCII

    7位编码将英文字符和一些常用的符号存诸为从0127的数值。

     

    2. ISO-8859-1

    法语、西班牙语和德语之类的西欧语言都使用叫做ISO-8859-1的编码系统(也叫做“latin-1”)。它使用7ASCII字符表示从0127的字符,但接着扩展到了128-255的范围来表示如n上带有一个波浪线(241),和u上带有两个点(252)的字符等等。可以说ASCIIISO-8859-1的子集。

     

    3. Unicode

        Unicode用一个2字节数字表示每个字符,从065535。每个 2 字节数字表示至少在一种世界语言中使用的一个唯一字符。(在多种语言中都使用的字符具有相同的数字码。)这样就确保每个字符一个数字,并且每个数字一个字符。Unicode数据永远不会模棱两可。Unicode使用相同的数字表示ASCIIISO-8859-1中的字符。只是这两种编码用一个字节表示,而Unicode用两个字节表示。所以Unicode表示这两种编码的字符时只要用低字节就可以了,高字节为0

     

    4. UTF-8

        UTF-8是一种变长的编码方式,每个UTF-8的编码可以是16个字节长。它将Unicode编码的字符采用变长的方式进行编码。对Unicode中属于ISO-8859-1的编码采用和ISO-8859-1相同的单字节编码。其他字符采用两字节以上的编码。实际上对于两个字节的Unicode编码,UTF-8只要三个字节即可表示。第一个字节由n11< 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. GB2312GBK

           这两种编码都是汉字的编码标准,其中前者是后者的子集。GBK编码的文本文档中对于ASCII中的字符用相同的单字节表示;对于汉字和汉语中的标点符号等采用双字节编码,其中高字节大于0x80,而ASCII的所有字符的编码均小于0x80, 所以ASCIIGBK的字符是可以混和起来的。GBK的字符集和Unicode进行转换是无规则的,需要转换表才能进行转换。

     

    6.下面给出我用Java语言写的UnicodeUTF-8转换的程序片段,供大家参考。

     

    因为Java语言的字符使用Unicode编码的,所以程序中是对UTF-8编码的字符串的字节数组和JavaString类型进行转换。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);

                         }

                  }

           }

  • 相关阅读:
    痞子衡嵌入式:利用i.MXRT1060,1010上新增的FlexSPI地址重映射(Remap)功能可安全OTA
    “既生 ExecutorService, 何生 CompletionService?”
    55
    .map() is not a function【js报错】
    内网穿透之流量代理转发
    JDK8 String类知识总结
    Java并发编程(07):Fork/Join框架机制详解
    数据源管理 | 分布式NoSQL系统,Cassandra集群管理
    Solon详解(三)- Solon的web开发
    Solon详解(二)- Solon的核心
  • 原文地址:https://www.cnblogs.com/qizhenglong/p/2864444.html
Copyright © 2011-2022 走看看