`

【Java基础专题】编码与乱码(05)---GBK与UTF-8之间的转换

 
阅读更多

【GBK转UTF-8】 在很多论坛、网上经常有网友问“ 为什么我使用 new String(tmp.getBytes("ISO-8859-1"), "UTF-8") 或者 new String(tmp.getBytes("ISO-8859-1"), "GBK")可以得到正确的中文,但是使用 new String(tmp.getBytes("GBK"), "UTF-8") 却不能将GBK转换成UTF-8呢?”

参考前面的
【Java基础专题】编码与乱码(03)----String的toCharArray()方法测试 一文,我们就知道原因了。因为如果客户端使用GBK、UTF-8编码,编码后的字节经过ISO-8859-1传输,再用原来相同的编码方式进行解码,这个过程是“无损的转换”---- 因为原始和最终的编码方式相同。

但是如果客户端使用GBK编码,到了服务器端要转换成UTF-8,或者相反的过程。想一想,字节还是那些字节,但是编码的规则变了。原来GBK编码后的4个字节要用UTF-8的每个字符3个字节的规则编码,怎么能不乱码呢?

所以从现在开始,不要再犯这种错误了。new String(tmp.getBytes("GBK"), "UTF-8") 这个过程,JVM内部是不会帮你自动对字节进行扩展以适应UTF-8的编码的。正确的方法应该是根据UTF-8的编码规则进行字节的扩充,即手动从2个字节变成3个字节,然后再转换成十六进制的UTF-8编码。

在这个专题的第一篇文章
【Java基础专题】编码与乱码(01)---编码基础 开头,我们就已经介绍了这个规则:
 ①得到每个字符的2进制GBK编码
 ②将该16进制的GBK编码转换成2进制的字符串(2个字节)
 ③分别在字符串的首位插入110,在第9位插入10,在第17位插入10三个字符串,得到3个字节
 ④将这3个字节分别转换成16进制编码,得到最终的UTF-8编码。


 

Unicode中文“艺”字: 827A

二进制的“艺”字编码:1000 0010 0111 1010

UTF-8的中文编码规则: 1110xxxx 10xxxxxx 10xxxxxx

UTF-8的“艺”字编码: 1110【1000】 10【0010】【01】 10【11】【1010】

UTF-8的转码过程解析: 8对应的1000被填入第一字节剩余的4位。2对应的0010被填入第2字节剩余的前4位。7对应的0111被拆开,前2位01被填入第2字节的后两位,后2位1被填入第3字节的前2位。A对应的1010被填入第3字节的后4位。

UTF-8的最终编码结果:11101000---对应E8;10001001---对应89;10111010---对应BA。所以最终的UTF-8编码就是%E8%89%BA
下面给出一个从网络上得到的Java转码方法,原文链接见:http://jspengxue.javaeye.com/blog/40781。下面的代码做了小小的修改

package example.encoding;

/** *//**
 * The Class CharacterEncodeConverter.
 */
public class CharacterEncodeConverter {

    /** *//**
     * The main method.
     * 
     * @param args the arguments
     */
    public static void main(String[] args) {

        try {
            CharacterEncodeConverter convert = new CharacterEncodeConverter();
            byte[] fullByte = convert.gbk2utf8("中文");
            String fullStr = new String(fullByte, "UTF-8");
            System.out.println("string from GBK to UTF-8 byte:  " + fullStr);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /** *//**
     * Gbk2utf8.
     * 
     * @param chenese the chenese
     * 
     * @return the byte[]
     */
    public byte[] gbk2utf8(String chenese) {
        
        // Step 1: 得到GBK编码下的字符数组,一个中文字符对应这里的一个c[i]
        char c[] = chenese.toCharArray();
        
        // Step 2: UTF-8使用3个字节存放一个中文字符,所以长度必须为字符的3倍
        byte[] fullByte = new byte[3 * c.length];
        
        // Step 3: 循环将字符的GBK编码转换成UTF-8编码
        for (int i = 0; i < c.length; i++) {
            
            // Step 3-1:将字符的ASCII编码转换成2进制值
            int m = (int) c[i];
            String word = Integer.toBinaryString(m);
            System.out.println(word);

            // Step 3-2:将2进制值补足16位(2个字节的长度) 
            StringBuffer sb = new StringBuffer();
            int len = 16 - word.length();
            for (int j = 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进制值
            byte b0 = Integer.valueOf(s1, 2).byteValue();
            byte b1 = Integer.valueOf(s2, 2).byteValue();
            byte b2 = Integer.valueOf(s3, 2).byteValue();
            
            // Step 3-7:把转换后的3个字节按顺序存放到字节数组的对应位置
            byte[] bf = new byte[3];
            bf[0] = b0;
            bf[1] = b1;
            bf[2] = b2;
            
            fullByte[i * 3] = bf[0];            
            fullByte[i * 3 + 1] = bf[1];            
            fullByte[i * 3 + 2] = bf[2];
            
            // Step 3-8:返回继续解析下一个中文字符
        }
        return fullByte;
    }
}

 最终的测试结果是正确的:string from GBK to UTF-8 byte:  中文。

但是这个方法并不是完美的!要知道这个规则只对中文起作用,如果传入的字符串中包含有单字节字符,如a+3中文,那么解析的结果就变成:string from GBK to UTF-8 byte:  ?????????中文了。为什么呢?道理很简单,这个方法对原本在UTF-8中应该用单字节表示的数字、英文字符、符号都变成3个字节了,所以这里有9个?,代表被转换后的a、+、3字符。

所以要让这个方法更加完美,最好的方法就是加入对字符Unicode区间的判断

UCS-2编码(16进制) UTF-8 字节流(二进制)
0000 - 007F 0xxxxxxx
0080 - 07FF 110xxxxx 10xxxxxx
0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx





汉字的Unicode编码范围为\u4E00-\u9FA5 \uF900-\uFA2D,如果不在这个范围内就不是汉字了。

【UTF-8转GBK】

道理和上面的相同,只是一个逆转的过程,不多说了


但是最终的建议还是:能够统一编码就统一编码吧!要知道编码的转换是相当的耗时的工作

分享到:
评论

相关推荐

    JAVA字符编码:Unicode,ISO-8859-1,GBK,UTF-8编码及相互转换

    ### JAVA字符编码详解:Unicode, ISO-8859-1, GBK, UTF-8 及其相互转换 #### 一、引言 在Java编程中,字符编码的管理和转换是一项基本而又重要的任务。不同的编码标准适用于不同的场景,而理解和掌握这些编码之间...

    关于JAVA字符编码:Unicode,ISO-8859-1,GBK,UTF-8编码及相互转换

    - 类似地,当从UTF-8转换到ISO-8859-1时,也会出现类似的情况: ```java String utf8Str = "中文"; byte[] isoBytes = utf8Str.getBytes("UTF-8"); String isoStr = new String(isoBytes, "ISO-8859-1"); // ...

    java文件编码GBK转utf8完美解决方案

    idea、Eclipse等项目导入.java文件中文乱码完美解决方案:文件夹下所有GBK编码的.java一键转为utf-8,操作方式:将GBK2UTF8.jar文件考到需要转码项目目录,在当前位置运行控制台,输入命令java -jar GBK2UTF8.jar,...

    eclipse中class乱码GBK-UTF-8转换工具

    这篇博客文章“eclipse中class乱码GBK-UTF-8转换工具”正是为了解决这个问题。 GBK是GB2312的扩展,包含了更多的汉字和其他字符,主要在中国大陆使用。UTF-8则是一种广泛使用的Unicode编码,支持世界上几乎所有的...

    java 编码 UTF-8、ISO-8859-1、GBK

    例如,如果数据库是UTF-8,JSP是GBK,可以使用 `new String(rs.getBytes(1),"UTF-8")` 将数据库中的UTF-8字节流转换为GBK字符串。反之,如果JSP是UTF-8,数据库是GBK,需要先将GBK字符串转换为字节流,然后再次转换...

    GBK与UTF-8之间的转换

    GBK与UTF-8之间的转换是一种常见的编码转换过程,在很多情况下,我们需要将GBK编码的字符串转换成UTF-8编码的字符串。然而,这种转换过程并不简单,需要我们了解编码的基本原理和规则。 首先,让我们了解一下GBK和...

    文件编码转换(utf8与gbk相互转换)

    使用这些资源,用户可以方便地在UTF-8和GBK之间进行文件编码的转换,解决编码不一致带来的问题,确保文本数据的正确性和可读性。对于经常处理中文文件的IT专业人士来说,理解和掌握编码转换技巧是非常必要的。

    批量将Java源代码文件的编码从GBK转为UTF-8

    老项目采用GBK编码格式,而新项目采用的UTF-8编码格式,如果直接把Java源代码复制到Eclipse中所有的中文信息会出现乱码。所以写了个小的方法类,将java文件的编码格式从GBK转UTF-8

    eclispe GBK转UTF-8乱码解决

    总的来说,解决Eclipse中GBK转UTF-8乱码问题的关键在于正确设置工作空间、项目、源代码和资源文件的编码,并且适时使用辅助工具进行批量转换。通过这些方法,可以避免编码不一致导致的乱码问题,提高开发效率。在...

    .java文件中GBK编码转UTF-8编码

    在eclispe的项目中,有存在项目字符集和工作空间字符集不匹配,该jar只能将项目文件中的.java结尾的文件转为utf8编码,并且源文件必须为gbk编码的,否则乱码

    Eclipse项目的GBK编码转为UTF-8插件

    Eclipse是一款广泛使用的Java开发集成环境,而GBK和UTF-8是两种常见的字符编码格式。在处理源代码时,编码的选择至关重要,因为它直接影响到字符的正确显示和处理。GBK编码是中国大陆广泛使用的汉字编码标准,它包含...

    简单的UTF-8与GBK之间相互转码工具

    本文将详细解析“简单的UTF-8与GBK之间相互转码工具”,并介绍相关的编码概念和实现方法。 首先,让我们理解编码的基础知识。字符编码是用来表示文本的规则,常见的有ASCII、GBK(GB2312的扩展)、UTF-8等。ASCII是...

    Java源码编码转换器 GBK TO UTF8 UTF8 To GBK(无源码)

    Java源码编码转换器是一款实用工具,主要用于将Java源代码文件从GBK编码转换为UTF-8编码,或者从UTF-8编码转换为GBK编码。在软件开发过程中,尤其是在处理中文字符时,编码问题是一个常见的挑战。GBK是中文环境下...

    乱码 编码方式解决 gbk ISO8859-1 utf8 编码

    本文将针对标题中的几种常见编码格式(GBK、ISO 8859-1、UTF-8)以及如何解决由这些编码方式引发的乱码问题进行深入探讨。 #### 一、编码概述 1. **GBK编码**:GBK是GB2312标准的扩展,支持简体中文,是Microsoft ...

    java将gbk文件批量转换成UTF-8

    在开发的时候经常碰到这样的情况,需要将原本编码格式为GBK的工程改成UTF-8来编码,设置之后,注释全都乱码了,一个一个改太麻烦,有了这个工具只用运行一下main方法,一键搞定 ps:如果是UTF-8转GBK,或是其他编码...

    如何使用Java代码将GBK编码格式的工程转换为UTF-8编码格式的工程.zip

    3. **转换编码**:对于检测到GBK编码的文件,使用`java.nio.file.Files`类的`readAllBytes`和`write`方法,配合`java.nio.charset.StandardCharsets`中的`UTF_8`常量,将文件内容从GBK编码转换为UTF-8编码。...

    批量转javaGBK编码文件到UTF-8

    总的来说,从GBK编码转换到UTF-8是解决Java源代码在Eclipse中可能出现的乱码问题的有效方法。通过编写Java程序或使用Eclipse插件,可以方便地对整个项目进行批量转换,确保所有文件都以正确的编码格式存储和处理。...

    如何将编码转换为UTF-8

    "UTF-8 编码转换详解" 1. UTF-8 编码的重要性:在 WEB 开发中,UTF-8 编码扮演着非常重要的角色,特别是在传递中文时,必须经过编码的动作,否则可能会出现乱码的情况。 2. 使用 URLEncoder.encode() 方法:在 ...

    Java源码编码转换器 v2.0 GBK TO UTF8

    该工具在之前的版本基础上进行了优化,修复了UTF-8转换后可能出现的乱码错误,确保了转换的准确性和稳定性。 在软件开发中,编码问题是一个常见的困扰,特别是当项目涉及到多种编码格式时。GBK是中国大陆广泛使用的...

    使用eclipse插件批量将Java源代码文件的编码从GBK(或其他编码)转为UTF-8

    当一个工程项目从GBK编码或其它非UTF-8编码格式需要转换为UTF-8时,开发者可能会遇到中英文乱码问题。Eclipse作为流行的Java集成开发环境,提供了便捷的插件来解决这类问题。 在Eclipse中进行批量转码通常涉及以下...

Global site tag (gtag.js) - Google Analytics