Chinaunix首页 | 论坛 | 博客
  • 博客访问: 488334
  • 博文数量: 111
  • 博客积分: 3146
  • 博客等级: 中校
  • 技术积分: 939
  • 用 户 组: 普通用户
  • 注册时间: 2009-07-07 11:23
个人简介

Nathing

文章分类

全部博文(111)

文章存档

2016年(2)

2015年(1)

2014年(31)

2012年(2)

2011年(9)

2010年(36)

2009年(30)

我的朋友

分类: Java

2009-11-15 15:04:38

如果你开发过的软件项目中涉及到多语言支持的问题,那么相信你没少碰到过乱码问题,然后在寻求解决问题的途径过程中被一些概念如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编码的字符。


  1. package com.merit.kaoshi;

  2. import java.io.ByteArrayOutputStream;
  3. import java.io.IOException;
  4. import java.io.OutputStream;

  5. public class UTF8Code
  6. {
  7.     public String utf8Bytes2String(byte[] buff)
  8.     {
  9.         if (buff == null)
  10.             return null;

  11.         StringBuffer sb = new StringBuffer();

  12.         int idx = 0;

  13.         if (buff[0] == (byte) 0xEF && buff[1] == (byte) 0xBB && buff[2] == (byte) 0xBF)
  14.             idx = 3;// Skip UTF8 header

  15.         while (idx < buff.length)
  16.         {
  17.             int hB = buff[idx] & 0xFF;
  18.             int bCnt = 0;
  19.             int check = 0x80;
  20.             for (int i = 0; i < 8; i++)
  21.             {
  22.                 if ((hB & check) != 0)
  23.                 {
  24.                     bCnt++;
  25.                     check >>= 1;
  26.                 }
  27.                 else
  28.                     break;
  29.             }

  30.             if (bCnt <= 1)
  31.             {
  32.                 char c = 0;
  33.                 c |= buff[idx] & 0xFF;
  34.                 sb.append(c);
  35.                 idx++;
  36.             }
  37.             else if (bCnt == 2)
  38.             {
  39.                 char c = 0;
  40.                 c |= buff[idx] & 0x03;
  41.                 c <<= 6;
  42.                 if ((buff[idx + 1] & 0xC0) != 0x80)
  43.                     return null;
  44.                 c |= buff[idx + 1] & 0x3F;
  45.                 idx += 2;
  46.                 sb.append(c);
  47.             }
  48.             else if (bCnt == 3)
  49.             {
  50.                 char c = 0;
  51.                 c |= buff[idx] & 0x0F;
  52.                 c <<= 6;
  53.                 if ((buff[idx + 1] & 0xC0) != 0x80)
  54.                     return null;
  55.                 c |= buff[idx + 1] & 0x3F;
  56.                 c <<= 6;
  57.                 if ((buff[idx + 2] & 0xC0) != 0x80)
  58.                     return null;
  59.                 c |= buff[idx + 2] & 0x3F;
  60.                 idx += 3;
  61.                 sb.append(c);
  62.             }
  63.             else
  64.                 return null;
  65.         }

  66.         return sb.toString();
  67.     }

  68.     public byte[] string2Utf8Bytes(String str)
  69.     {
  70.         if (str == null)
  71.             return null;

  72.         ByteArrayOutputStream bos = new ByteArrayOutputStream();
  73.         try
  74.         {
  75.             string2Utf8Stream(str, bos);
  76.         }
  77.         catch (IOException e)
  78.         {
  79.             e.printStackTrace();
  80.         }
  81.         return bos.toByteArray();
  82.     }

  83.     public void string2Utf8Stream(String str, OutputStream os) throws IOException
  84.     {
  85.         if (str == null || os == null)
  86.             return;

  87.         for (int i = 0; i < str.length(); i++)
  88.         {
  89.             char c = str.charAt(i);
  90.             if (c < 0x80)
  91.             {
  92.                 os.write((byte) c);
  93.             }
  94.             else if (c >= 0x80 && c < 0x100)
  95.             {
  96.                 int hi = c >> 6;
  97.                 hi |= 0xC0;
  98.                 int lo = c & 0x3F;
  99.                 lo |= 0x80;
  100.                 os.write(hi);
  101.                 os.write(lo);
  102.             }
  103.             else
  104.             {
  105.                 int first = c >> 12;
  106.                 first |= 0xE0;
  107.                 int second = c >> 6;
  108.                 second &= 0x3F;
  109.                 second |= 0x80;
  110.                 int third = c & 0x3F;
  111.                 third |= 0x80;
  112.                 os.write(first);
  113.                 os.write(second);
  114.                 os.write(third);
  115.             }
  116.         }
  117.     }
  118. }


参考:由一节废电池引起

阅读(782) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~