美文网首页
乱码问题(一)编码那些事

乱码问题(一)编码那些事

作者: 风轻云淡_z | 来源:发表于2019-08-20 00:33 被阅读0次

我们知道在计算机里面存储的最小单位为bit,而8个bit构成了一个字节(byte)。字节是我们能用编程语言控制读写的最小单位。如果我们想一个bit一个bit写的话只能去对每个比特位进行缓存然后左移相加,当凑齐8个时再按照一个字节进行写入。

字符和字节是什么关系

字符,也会是我们常见的文字符号,比如A、B、C、1、2、3、你、好、啊,这些字符构成了我们的文字,而他们的组合又构成了我们的语言。当然如果狭义的来说,字符还包括很多看不见的转义字符。
字节是计算机存储的单位,而字符是人的单位。人的单位和计算机的单位又不是完全等同的,当我们想把字符在计算机上表示时,就必须要做一些转换,而这个转换规则,就是我们常说的编码。而我们常见的乱码原因其实都是源于写入编码和读取编码不一致。
在HTML的meta标签里有个charset属性,其作用就是设置读取的编码,如果不设置,则会按照操作系统默认的编码进行读取,在windows下为GBK,Linux下为UTF-8。下面一个最基本的网页,我们以UTF-8编码进行保存

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
这是一段中文文字
</body>
</html>
在浏览器打开没问题,

当我们把

 <meta charset="UTF-8">

这一行删掉再打开时,由于没设置编码,故浏览器会采用默认的GBK编码进行读取,所以就会出现下面的乱码。


编码的历史

最早的ASCII码

你可能经常听到什么GBK、UTF-8、ASCII、ISO-8859-1......这些乱七八糟的编码名词,心中可能会有疑问为什么会有这么多的编码,只存在一个不好吗,这样也就不存在那些恶心的乱码问题了。其实,这些东西表面上看起来很乱,如果我们从历史的角度上缕一缕,就会明白为什么会有这么多的编码了。
我们知道,计算机早期基本上都是美国人在研究和使用。为了表示方便,他们就想能否用一系列数字来代替那些字符。于是就出来ASCII就出来了,在ASCII码里,0-32有不表示字符,他们有自己特殊的含义,比如7代表响铃、10代表换行。从33到126每一个分别代表一个特定的字符,比如57代表阿拉伯数字9、85代表英文字母U。这样当计算机遇到这些数字时就会显示对应代表的字符。
ASCII码采用一个字节来编码一个字符,也就是计算机每读到一个字节,就会去ASCII码表里查找它对应的字节,然后把它给显示出来。

各种扩展ASCII编码百花齐放时代

随着世界的发展,计算机也逐渐传到各个国家,这时就存在一个问题了,如何在计算机上表示本国的文字。毕竟计算机毕竟是人家美国发明的,他们刚开始设计的时候也没有考虑太多,所以其他国家的文字如何在计算机上显示就成了一个问题了。就以中文为例,ascii码是采用一个字节即八位来表示一个字符的,所以理论上最多能存2^8即256种字符,就算这样,也没法完全表示所有的中文字符啊,就拿比较常用的《新华字典》来说,其里面也有10000多个汉字。而且如果我们要重写ascii码的话,那么在中文机器上又无法正确显示英文字符了。所以现在面临着两个问题

  1. 如何表示这些中文字符
  2. 在表示这些字符的时候如何做到与ascii码兼容

但这丝毫难不倒我们聪明的中国人民,既然一个字节表示不了,那我两个总可以了吧,我们知道两个字节也就是16位,最多能表示2^16即65536个字符,对付常见的中文字符是足够了。但是另一个问题该怎么解决呢,这时,我们聪明的中国人民又想到了,既然前127位被你用了,那我就从127后面开始编码不就行了,这样当读取的字节值小于127时,我们就把它当成ASCII码来处理,当读取到的值大于127时,我们就再把它后面一位字节读取下,然后把这两个字节翻译成对应的汉字。然后最早的中文编码GB2312就出来了,后来微软对GB2312进行扩展,同时向下兼容GB2312,制定了GBK编码,最早出现于Windows 95简体中文版中,这也是我们现在windows计算机中文默认使用的编码。后来国家又发布了GB 18030编码标准,对GB2312进行了一些补充。在这里需要补充的是GBK是微软的标准并不是国家标准。

下面我们用代码演示具体编码

下面一段代码用来获取字符串s1用GB2312编码后的字符数组并输出

    @Test
    public void testGbk() throws UnsupportedEncodingException
    {
        String s1 = "中国ABC";
        byte[] bytes1 = s1.getBytes("GB2312");
        for(byte b: bytes1)
        {
            System.out.print(b + " ");
        }
    }

得到下面输出结果


这里由于byte在java里默认是有符号类型的,所以最高位的1被当成符号位了输出了负数。具体解释下就是ascii码在0-127之间,所以对应的8位比特最高为永远为0,最大的127对应的8位比特为0111 1111,而GB2312是从128开始的,所以对应的第一个bit位位一,而在计算机中,第一位是当作符号位处理的,中文编码是从128开始的,这时第一位永远是1,所以会输出负值。( 具体怎么转换请搜索原码、反码、补码关键词)
我们对输出结果进行下改进,以便更直观的看到编码结果
    @Test
    public void testGbk() throws UnsupportedEncodingException
    {
        String s1 = "中国ABC";
        byte[] bytes1 = s1.getBytes("GB2312");
        for(byte b: bytes1)
        {
            System.out.print(Integer.toHexString(b & 0xff) + " ");
        }
    }

这里我们把它强转成int并通过& oxff屏蔽掉变成int后多出来的位,最后以16进制输出。结果如下


通过刚才以及现在的输出我们可以推断d6 d0的GB2312码,b9 fa的GB2312码,而41 42 43刚好对应ASCII码的41 42 43。所以在GB2312码里中文字符占两个字节,英文字符占一个字节
我们把编码换成GBK,得到下面输出

跟刚才的一样。GBK是兼容GB2312的,可以把GB2312看成GBK的子集。

就这样,各个国家也都开始像中国这样通过扩展ASCII码来制定自己的编码,于是出现了一堆编码,比如繁体字的BIG5,日文的Shift_JIS,韩文的EUC_KR......但这些编码面临着一个很大的问题,它们之间互相都不兼容。

统一标准的Unicode

刚才提到了各个国家都通通的去制定自己的文字编码,但是这些文字编码又互相不兼容,所以当一份文字通过互联网在不同国家传递时很容易出现乱码问题。
后来出现了一个叫国际标准化组织ISO和Unicode的协会,他们像设计一个字符集,可以把全世界的文字都包含进去,以图统一编码。而这个字符集就是Unicode字符集。注意Unicode是一个字符集,不是某一个编码。我们知道中文是不包括拉丁文的,同样拉丁文也不包括俄罗斯文,所以Unicode就是一个即包含了中文,又包含了拉丁文、日文、俄文......的字符集,我们常用的emoji表情也是Unicode里面的。总之你可以在里面找到任何一个国家的字符。
而在Unicode里每一个字符都有对应的Unicode码,比如U+4E2D代表U+56fd代表 。但是这只代表了符号的二进制码,而将它存入计算机依然需要进行编码。而Unicode对应的编码规则有很多,比如我们常见的UTF-8,java里使用的 UTF-16BE编码。而不同Unicode编码会有很大差别。

    @Test
    public void testUTF8() throws UnsupportedEncodingException
    {
        String s1 = "中国ABC";
        byte[] bytes1 = s1.getBytes("UTF-8");
        for(byte b: bytes1)
        {
            System.out.print(Integer.toHexString(b & 0xff) + " ");
        }
    }

得到如下结果


image.png

我们可以看到UTF-8编码中中文占三个字节,英文占1个字节

如果采用UTF-16BE,会得到下面结果


在UTF-16BE编码中,不管是中文还是英文,都统统占用两个字节
可以发现UTF-8兼容ASCII码,所以用的比较多。

在unicode里有许多特殊转义字符,利用它我们可以做出许多特殊的效果。比如之前传的比较火的千万不要动到黑点,手机会卡死机 <> ‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎ ‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎ ‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎ ‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎ ‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎ ‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎ ‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎ ‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎ ‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏ ‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏⁧erehhcuot
这句话,其实就是Unicode特殊转义字符。在Unicode里有两个字符表示书写方向,这两个字符宽度位0,所以不会显示出来,而在小圆点旁边写入了几千个这样的字符,而对应这些字符,系统需要花点时间来进行渲染,所以但你点击的时候,手机会出现卡顿。

乱码问题(二)常见乱码情况分析与解决方法

相关文章

  • 乱码问题(一)编码那些事

    我们知道在计算机里面存储的最小单位为bit,而8个bit构成了一个字节(byte)。字节是我们能用编程语言控制读写...

  • 插入数据库出现中文乱码问题

    插入数据库出现中文乱码问题 出现这种乱码问题,肯定是编码除了问题,编码和解码不是同一种编码格式就会出现乱码情况! ...

  • Java 字符编码

    任何乱码问题都是因为编码和解码不一致造成。出现乱码时只需将乱码按照当前编码方式重新进行编码,然后在按照编码时所用的...

  • java基础——servlet乱码问题

    servlet 乱码问题 1. 乱码的本质 乱码的本质就是文件或者流存的编码与读的编码不一样,就会导致乱码。 2....

  • 简单介绍计算机常用编码

    计算机常用编码 常用编码介绍 ASCII码表 乱码产生的原因 解决乱码 notepad++等记事本中的乱码问题 常...

  • 【MySQL实战02】CentOS 7 下修改 MySQL 字符

    乱码问题: 由于 MySQL 编码原因会导致数据库出现乱码的问题。 解决办法: 修改 MySQL 数据库的字符编码...

  • html页面中文显示乱码问题

    html页面中文显示乱码问题 html页面中出现中文时可能在前端显示为乱码。 问题原因: 页面的显示编码和存储编码...

  • 统一全站字符编码案例

      我们在现实生活中,中文网站的编码都需要进行设置,否则会出现乱码,我们之前已经讲解过解决乱码问题的方法,但是那些...

  • 第二课 PHP解决乱码问题

    数据库或者页面输出中文乱码,但是英文以及数字却没有乱码的问题,一般出现这种问题都是编码引起的,所以保持所有编码一致...

  • swift 带中文的字符串会出现乱码

    出现中文乱码,大概率就是编码问题导致的,使用GBK/GB2312进行编码

网友评论

      本文标题:乱码问题(一)编码那些事

      本文链接:https://www.haomeiwen.com/subject/jvhysctx.html