GBK转UTF-8编码

能处理1, 2, 3个字节的英文,特殊字符,中文

 

http://www.cnblogs.com/chenwenbiao/archive/2011/08/11/2134503.html  utf-8编码规则

http://www.jianshu.com/p/07b578adfbf8 utf-8介绍

http://www.blogjava.net/pengpenglin/archive/2010/02/22/313669.html  普通代码实现

http://www.iteye.com/problems/94345  位运算

http://tool.lu/hexconvert/  各种进制在线转换工具

 

http://baike.baidu.com/link?url=X8kyAipcbMOtbpsMb0o-Zs20OSpKepuYFNfEdCvmezlCSKY-a4wUGuvQ9dZOa90zVCHKVq0cddRH3q7O3mBLyq  十六进制

 

 

互联网的普及,强烈要求出现一种统一的编码方式。UTF-8就是在互联网上使用最广的一种unicode的实现方式。其他实现方式还包括UTF-16UTF-32,不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8Unicode的实现方式之一。

UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8的编码规则很简单,只有二条:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

下表总结了编码规则,字母x表示可用编码的位。

Unicode符号范围 | UTF-8编码方式

(十六进制) | (二进制)

--------------------+---------------------------------------------

0000 0000-0000 007F | 0xxxxxxx

0000 0080-0000 07FF | 110xxxxx 10xxxxxx

0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx

0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

下面,还是以汉字“严”为例,演示如何实现UTF-8编码。

已知“严”的unicode4E25100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此“严”的UTF-8编码需要三个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。

然后,从“严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,“严”的UTF-8编码是“11100100 10111000 10100101”,转换成十六进制就是E4B8A5

 

 

 

 

2个字节的 GBK字符·“ (姓名间隔符号,在搜狗输入法下,输入数字1左边那个点号键) UTF-8编码过程:

到每个字符的2进制GBK编码

 

 int m = (int) c[i];  -- 得到·的十进制数为183,转为二进制为 1011 0111

 

②将该16进制的GBK编码转换成2进制的字符串(2个字节)

2字节的补齐11位,在前面补0 (图片第二行有11X,所以补齐11位)

000 1011 0111

 

 

③分别在字符串的首位插入110,在第9位插入10,得到2个字节

110 000 10 10 11 0111

 

④将这2个字节分别转换成16进制编码,得到最终的UTF-8编码。

 

// Step 2: UTF-8使用3个字节存放一个中文字符,所以长度必须为字符的3

        byte[] fullByte = newbyte[2];  

        String  tot = "1100001010110111";

        String s1 = tot.substring(0, 8);

        String s2 = tot.substring(8, 16);

       

       // Step 3-6:最后的步骤,把代表3个字节的字符串按2进制的方式

       // 进行转换,变成2进制的整数,再转换成16进制值

       Integer iiInteger.valueOf(s1, 2);

       byteb0 = Integer.valueOf(s1, 2).byteValue();

       byteb1 = Integer.valueOf(s2, 2).byteValue();

      

       // Step 3-7:把转换后的3个字节按顺序存放到字节数组的对应位置

       byte[] bf = newbyte[2];

       bf[0] = b0;

       bf[1] = b1;

 

       fullByte[0] = bf[0];           

       fullByte[1] = bf[1];    

      

       return fullByte;

 

 

 

以下是完整能处理1-3个字节的中文+英文字符+特殊符号的例子(代码借鉴了网上资源,只有处理2个字节的部分是新加的)

 

package example.encoding;

 

publicclass GBK2UTF8 {

 

        /**

         * The main method.

         *

         * @param args the arguments

         */

        publicstaticvoid main(String[] args) {

 

            try {

               System.out.println(String.valueOf(183));

               System.out.println((char) 1500);

               GBK2UTF8 convert = new GBK2UTF8();

                byte[] fullByte = convert.gbk2utf8("לڥ木西·阿拉ÁÉΣ");

                String fullStr = new String(fullByte, "UTF-8");

                System.out.println("string from GBK to UTF-8 byte:" + fullStr);

               

                byte[] fullByte2 = convert.getUTF8BytesFromGBKString("לڥ木西·阿拉ÁÉΣ");

                String fullStr2 = new String(fullByte2, "UTF-8");

                System.out.println("2 - string from GBK to UTF-8 byte:" + fullStr2);

               

               

 

            } catch (Exception e) {

                e.printStackTrace();

            }

        }

 

        /**

         * Gbk2utf8.

         *

         * @param chenese the chenese

         *

         * @return the byte[]

         */

        publicbyte[] gbk2utf8(String chiness) {

           

            // Step 1: 得到GBK编码下的字符数组,一个中文字符对应这里的一个c[i]

            charc[] = chiness.toCharArray();

           

            // Step 2: UTF-8使用3个字节存放一个中文字符,所以长度必须为字符的3

            byte[] fullByte = newbyte[3 * c.length];

            intk = 0;

            // Step 3: 循环将字符的GBK编码转换成UTF-8编码

            for (inti = 0; i < c.length; i++) {

               

                // Step 3-1:将字符的ASCII编码转换成2进制值

                intm = (int) c[i];

                String word = Integer.toBinaryString(m);

               

                System.out.println(word);

               

                if (m < 128 && m > 0) {

                  byteb = (byte) m;

                  byte[] bf = newbyte[1];

                   bf[0] = b;

                  fullByte[k++] = bf[0];

                  continue;

                } elseif (m >= 128 && m <= 1775) {

                  // 处理2个字节的特殊字符,例如姓名分隔符 · (二进制1100001010110111

 

                  // Step 3-2:将2进制值补足16(2个字节的长度)

                  //UCS-2编码(16进制)   UTF-8 字节流(二进制)

                  //0000 - 007F 0xxxxxxx

                  //0080 - 07FF 110xxxxx 10xxxxxx

                  //0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx

 

                   StringBuffer sb = new StringBuffer();

                  

                   //2行有11X,所以要补齐11

                   intlen = 11 - word.length();

                   for (intj = 0; j < len; j++) {

                       sb.append("0");

                   }

                   // Step 3-3:得到该字符最终的2进制GBK编码

                   // 形似:00010110111

                   sb.append(word);

                   System.out.println(sb.toString());

                   // Step 3-4:最关键的步骤,根据UTF-8的汉字编码规则,首字节

                   // 110开头,次字节以10开头。在原始的2进制

                   // 字符串中插入标志位。最终的长度从11--->16

                   sb.insert(0, "110");

                   sb.insert(8, "10");

                   System.out.println(sb.toString());

                   // 00010110111 得到1100001010110111

                   // Step 3-5:将新的字符串进行分段截取,截为3个字节

                   String s1 = sb.substring(0, 8);

                   String s2 = sb.substring(8, 16);

 

                   // Step 3-6:最后的步骤,把代表3个字节的字符串按2进制的方式

                   // 进行转换,变成2进制的整数,再转换成16进制值

                   byteb0 = Integer.valueOf(s1, 2).byteValue();

                   byteb1 = Integer.valueOf(s2, 2).byteValue();

 

                   // Step 3-7:把转换后的3个字节按顺序存放到字节数组的对应位置

                   byte[] bf = newbyte[2];

                   bf[0] = b0;

                   bf[1] = b1;

 

                   fullByte[k++] = bf[0];           

                   fullByte[k++] = bf[1];           

                   continue;

                } else {

                  // 处理3个字节的中文

                  // Step 3-2:将2进制值补足16(2个字节的长度)

                   StringBuffer sb = new StringBuffer();

                   intlen = 16 - word.length();

                   for (intj = 0; j < len; j++) {

                       sb.append("0");

                   }

                   // Step 3-3:得到该字符最终的2进制GBK编码

                   // 形似:1000 0010 0111 1010

                   sb.append(word);

                  

                   // Step 3-4:最关键的步骤,根据UTF-8的汉字编码规则,首字节

                   // 1110开头,次字节以10开头,第3字节以10开头。在原始的2进制

                   // 字符串中插入标志位。最终的长度从16--->16+3+2+2=24

                   sb.insert(0, "1110");

                   sb.insert(8, "10");

                   sb.insert(16, "10");

                   System.out.println(sb.toString());

 

                   // Step 3-5:将新的字符串进行分段截取,截为3个字节

                   String s1 = sb.substring(0, 8);

                   String s2 = sb.substring(8, 16);

                   String s3 = sb.substring(16);

 

                   // Step 3-6:最后的步骤,把代表3个字节的字符串按2进制的方式

                   // 进行转换,变成2进制的整数,再转换成16进制值

                   byteb0 = Integer.valueOf(s1, 2).byteValue();

                   byteb1 = Integer.valueOf(s2, 2).byteValue();

                   byteb2 = Integer.valueOf(s3, 2).byteValue();

                  

                   // Step 3-7:把转换后的3个字节按顺序存放到字节数组的对应位置

                   byte[] bf = newbyte[3];

                   bf[0] = b0;

                   bf[1] = b1;

                   bf[2] = b2;

                  

                   fullByte[k++] = bf[0];            

                   fullByte[k++] = bf[1];           

                   fullByte[k++] = bf[2];

                  

                   // Step 3-8:返回继续解析下一个中文字符

                   continue;

                }

            }

            if (k < fullByte.length) {

              byte[] tmp = newbyte[k];

              System.arraycopy(fullByte, 0, tmp, 0, k);

              returntmp;

            }

            returnfullByte;

        }

       

        publicstaticbyte[] getUTF8BytesFromGBKString(String gbkStr) { 

            intn = gbkStr.length(); 

            byte[] utfBytes = newbyte[3 * n]; 

            intk = 0; 

            for (inti = 0; i < n; i++) { 

                intm = gbkStr.charAt(i); 

                if (m < 128 && m >= 0) { 

                    utfBytes[k++] = (byte) m

                    continue

                } elseif (m >= 128 && m <= 1775) {

                  //UCS-2编码(16进制)   UTF-8 字节流(二进制)

                  //0000 - 007F 0xxxxxxx

                  //0080 - 07FF 110xxxxx 10xxxxxx

                  //0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx

                 

                  // · 二进制 1011 0111

                  // 0xc0 = 11000000

                  // 0x80 = 10000000

                  // 0x3f = 111111

                 

                  utfBytes[k++] = (byte) (0xc0 | (m >> 6));  // · 二进制 1011 0111 只取前2

                   utfBytes[k++] = (byte) (0x80 | (m & 0x3f));  //

                   continue;

                }

                utfBytes[k++] = (byte) (0xe0 | (m >> 12)); 

                utfBytes[k++] = (byte) (0x80 | ((m >> 6) & 0x3f)); 

                utfBytes[k++] = (byte) (0x80 | (m & 0x3f)); 

            } 

            if (k < utfBytes.length) { 

                byte[] tmp = newbyte[k]; 

                System.arraycopy(utfBytes, 0, tmp, 0, k); 

                returntmp

            } 

            returnutfBytes

        } 

    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值