前情提要:编码相关

编码分为unicode码与非unioncode码,所有的非unioncode码都是以美国的ASCII码作为基础发展而来,下面先讲解ASCII码系列编码(非unioncode码),再讲unioncode码。

非unioncode码

  • ASCII码虽然占用一个字节(8位),可以表示0-255个字符,但当初设计的时候只需要用0-127个即可,其中32-126是我们常见的大部分英文及字符,而0-31和127都是一些不可打印字符。以下列出一些常见的不可打印字符:
    常见的不可打印字符

  • ASCII码虽然对美国是够用了,但对其他国家是不行的。其他国家为了兼容ASCII码,于是将ASCII码的最高位置为1,在最高位为1的时候扩展自己国家需要的编码规则,在这些扩展的编码中,在西欧国家中流行的是ISO8859-1和Windows-1252,在中国式GB2312、GBK、GB18030和Big5。美国和西欧国家的编码只需要一个字节就够用了,但对于我们国家来讲,范围需要更大。比如GB2312就需要用两个字节来代表一个汉字(分别称作低位字节和高位字节)。当然,这两个字节的最高位都为1。GBK作为GB2312的延伸,允许低位字节的最高位为0,这时候你或许有疑问,在解析二进制流的时候,我们如何分别该字节代表的是ASCII码还是中文汉字的低字节位呢?不要忘了,对于GBK编码,中文汉字规定为两字节代表一个汉字,而汉字的高位字节一定是1,那么在解析的时候,如果第一个字节最高位为1,就连续解析两个字节当做汉字解码即可。最后简单说一下GB18030和Big5即可。前者在GBK的基础上采用了变长字节编码,分为四字节和两字节,两字节编码和GBK一样;Big5是对台湾以及香港的一些繁体字进行了编码

unioncode码

上面的各种编码规则虽然都是基于ASCII码,但每个国家的编码都不会考虑其他国家的编码,比如GB2312、GBK、GB18030三者是兼容的,但和Big5不兼容,和西欧的编码更不兼容,不兼容就会出现乱码。因此有没有一种编码可以统一世界上所有的字符呢?


有的,这就是unicode编码。unicode做了一件事,就是给世界上所有字符都分配了一个唯一的数字编号。大部分常用的字符都在0x0000-0xFFFF之间,即65535个数字之内。每个字符都有一个unicode编号,这个编号一般写成十六进制,在前面加U+。
unicode编码除了做了“大一统”的编码工作,还有什么是和其他编码不一样的地方的呢,unicode虽然给所有字符分配了唯一的数字编号,但并没有规定这个编号怎么对应到二进制表示,这是与上面介绍的其他编码是不同的。那编号怎么对应到二进制表示呢?有很多种方案,主要有UTF-32、UTF-16和UTF-8。
  • UTF16和UTF32都是定长字节编码,你可以猜想到前者是两个字节,后者是四个字节编码(UTF-16使用两个或四个字节表示一个字符,Unicode编号范围在65536以内的占两个字节,超出范围的占4个字节)
  • 关键介绍的编码是UTF-8。UTF-8使用的是变长字节编码,每个字符使用的字节个数与其unicode编号的大小有关,编号小的使用的字节就少,编号打的使用的字节就多,使用的字节数为1-4不等
  • 具体来说,各个unicode编号范围对应的二进制格式如下图所示
    各个unioncode编号范围对应的二进制格式

-从上图可以看到一些编码的特征。对于编号小于128的,编码和ASCII码一样,最高位为0.其他编号的第一个字节有特殊含义,最高位有几个连续的1就表示用几个字节表示,而其他字节都已10开头。这样规定当然是为了变长编码的解析考虑。和UTF-32/UTF-16不同,UTF-8是兼容 ASCII的,对于大部分中文而言,一个中文字符需要三个字节表示

编码转换和乱码

unicode的出现相当于为所有各式各样的编码规则起到了一个参照的作用,因此我们可以利用unicode来实现转码。比如我们为汉字“马”编制了一个表格,里面有“马”的不同编码的实现,如图:
“马”的不同编码实现
那么如果我们想把“马”从GB1830转换为UTF-8,那就是先拿着“马”的GB1830编码去这张表格找到“马”的unicode编号,再根据unicode编号去找“马”的UTF-8编码,这样就实现了编码的转换

乱码的原因

解析错误

最简单的乱码原因 : 加密的编码方式和解密的编码方式不一致。很多时候利用文本编辑器可以切换查看编码的方式就可以解决这个问题,但有的时候这样也是解决不了的

在错误的解析基础上又进行了编码转换

那这种情况你怎么改变查看方式都不对,下面就是文章参考的书《java编程的逻辑》中的截图
在错误的解析基础上又进行了编码转换
但你说这种情况会出现么,谁会傻呵呵的将乱码再进行二次编码呢?答案是会。计算机程序为了便于统一处理,经常会将所有编码转换为一种方式,比如utf-8,这种情况下就会出现第二种乱码的情况。

从乱码中恢复

第二种情况的解码产生逻辑图

然后你就能明白书里在说什么了

使用java恢复乱码

    public static void recover(String str)
            throws UnsupportedEncodingException {
        String[] charsets = new String[]{
                "windows-1252","GB18030","Big5","UTF-8","gb2312","iso-8859-1"};
        for(int i=0;i<charsets.length;i++){
            for(int j=0;j<charsets.length;j++){
                if(i!=j){
                    String s = new String(str.getBytes(charsets[i]),charsets[j]);
                    System.out.println("---- 原来编码(A)假设是: "
                            +charsets[j]+", 被错误解读为了(B): "+charsets[i]);
                    System.out.println(s);
                    System.out.println();
                }
            }
        }
    }

IT资料领取请添加微信:fiji12458

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值