分析乱码产生的原因及常见乱码的解决方法
分析乱码产生的原因及恢复乱码
- 1、为什么需要编码
- 2、常见编码
- ASCII
- ISO-8859-1(扩展ASCII编码)
- Windows-1252
- GB2312
- GBK(扩展GB2312)
- GB18030(兼容GB2312,GBK)
- Big5
- Unicode编码集
- UTF-32
- UTF-16
- UTF-8
- 几种编码的比较
- 编码转换
- 3. 乱码产生的原因
- 4. 尝试恢复乱码
在了解怎么解决乱码之前,很有必要了解几种编码格式。
1、为什么需要编码
主要有以下几个原因
- 计算机中存储信息的最小单元是一个字节即 8 个 bit,所以能表示的字符范围是 0~255 ;
- 人类要表示的符号太多,无法用一个字节来完全表示;
- 要解决这个问题,就需要编码
2、常见编码
ASCII
ASCII(American Standard Code for Information Interchange,美国信息互换标准代码),是现今最通用的单字节编码系统。
ASCII 的高位是0,低 7 位表示具体字符。共有 128个字符,0-31、127 是控制字符如换行回车删除等;32~126 是特殊字符、字母、数字等。
具体能表示的字符可见 ASCII码对照表。
为了保持与ASCII 码的兼容性,一般都是将最高位设置为1。也就是说,当最高位为0时,表示ASCII 码,当为1时就是各个国家自己的字符。
在这些扩展的编码中,在西欧国家中流行的是ISO-8859-1和Windows-1252,在中国是GB2312,GBK,GB18030和Big5,我们逐个来看下这些编码。
ISO-8859-1(扩展ASCII编码)
128 个字符显然是不够用的,于是 ISO 组织在 ASCII 码基础上又制定了一些列标准用来扩展 ASCII 编码,它们是 ISO-8859-1 ~ ISO-8859-15,其中 ISO-8859-1 涵盖了大多数西欧语言字符,应用最广泛。
ISO-8859-1 仍然是单字节编码。它向下兼容ASCII,它总共能表示 256 个字符。
具体能表示的字符可见 ISO-8859-1字符
Windows-1252
ISO 8859-1虽然号称是标准,用于西欧国家,但它连欧元(€) 这个符号都没有,因为欧元比较晚,而标准比较早。实际使用中更为广泛的是Windows-1252编码,这个编码与ISO8859-1基本是一样的,区别 只在于数字128到159,Windows-1252使用其中的一些数字表示可打印字符。
这个编码中加入了欧元符号以及一些其他常用的字符。基本上可以认为,ISO-8859-1已被Windows-1252取代,在很多应用程序中,即使文件声明它采用的是ISO-8859-1编码,解析的时候依然被当做Windows-1252编码。
GB2312
它是双字节编码,总的编码范围是 A1-F7,其中从 A1-A9 是符号区,总共包含 682 个符号,从 B0-F7 是汉字区,包含 6763 个汉字。
GBK(扩展GB2312)
是为了扩展 GB2312,加入更多的汉字,它的编码范围是 8140~FEFE(去掉 XX7F)总共有 23940 个码位,它能表示 21003 个汉字, 兼容GB2312 ,也就是说用 GB2312 编码的汉字可以用 GBK 来解码,并且不会有乱码。
GB18030(兼容GB2312,GBK)
GB18030向下兼容GBK,增加了五万五千多个字符,共七万六千多个字符。包括了很多少数民族字符,以及中日韩统一字符。
用两个字节已经表示不了GB18030中的所有字符,GB18030使用变长编码,有的字符是两个字节,有的是四个字节。
在两字节编码中,字节表示范围与GBK一样。在四字节编码中,第一个字节的值从0x81到0xFE,第二个字节的值从0x30到0x39,第三个字节的值从0x81到0xFE,第四个字节的值从0x30到0x39。
解析二进制时,如何知道是两个字节还是四个字节表示一个字符呢?看第二个字节的范围,如果是0x30到0x39就是四个字节表示,因为两个字节编码中第二字节都比这个大。
Big5
Big5是针对繁体中文的,广泛用于台湾香港等地。
Big5包括1万3千多个繁体字,和GB2312类似,一个字符同样固定使用两个字节表示。在这两个字节中,高位字节范围是0x81-0xFE,低位字节范围是0x40-0x7E和0xA1-0xFE。
Unicode编码集
以上我们介绍了中文和西欧的字符与编码,但世界上还有很多别的国家的字符,每个国家的各种计算机厂商都对自己常用的字符进行编码,在编码的时候基本忽略了别的国家的字符和编码,甚至忽略了同一国家的其他计算机厂商,这样造成的结果就是,出现了太多的编码,且互相不兼容。
世界上所有的字符能不能统一编码呢?可以,这就是Unicode。
Unicode 做了一件事,就是给世界上所有字符都分配了一个唯一的数字编号,这个编号范围从0x000000到0x10FFFF,包括110多万。但大部分常用字符都 在0x0000到0xFFFF之间,即65536个数字之内。每个字符都有一个Unicode编号,这个编号一般写成16进制,在前面加U+。大部分中文 的编号范围在U+4E00到U+9FA5,例如,"马"的Unicode是U+9A6C。
Unicode就做了这么 一件事,就是给所有字符分配了唯一数字编号。它并没有规定这个编号怎么对应到二进制表示,这是与上面介绍的其他编码不同的,其他编码都既规定了能表示哪些 字符,又规定了每个字符对应的二进制是什么,而Unicode本身只规定了每个字符的数字编号是多少。
那编号怎么对应到二进制表示呢?有多种方案,主要有UTF-32, UTF-16和UTF-8。
UTF-32
这个最简单,就是字符编号的整数二进制形式,四个字节。
但有个细节,就是字节的排列顺序,如果第一个字节是整数二进制中的最高位,最后一个字节是整数二进制中的最低位,那这种字节序就叫“大端”(Big Endian, BE),否则,正好相反的情况,就叫“小端”(Little Endian, LE)。对应的编码方式分别是UTF-32BE和UTF-32LE。
可以看出,每个字符都用四个字节表示,非常浪费空间,实际采用的也比较少。
UTF-16
- UTF-16 具体定义了 Unicode 字符在计算机中存取方法。
- UTF-16 用两个字节来表示 Unicode 转化格式,不论什么字符都可以用两个字节表示,两个字节是 16 个 bit,所以叫 UTF-16。
- UTF-16 表示字符非常方便,每两个字节表示一个字符,这个在字符串操作时就大大简化了操作,这也是 Java 以 UTF-16 作为内存的字符存储格式的一个很重要的原因。
- 从 UTF-16 编码规则来看,仅仅将字符的高位和低位进行拆分变成两个字节。特点是编码效率非常高,规则很简单,由于不同处理器对 2 字节处理方式不同,Big-endian(高位字节在前,低位字节在后)或 Little-endian(低位字节在前,高位字节在后)编码。如果高位存放在前面就叫大端(BE),编码就叫UTF-16BE,否则就叫小端,编码就叫UTF-16LE。
UTF-8
- UTF-16 统一采用两个字节表示一个字符,虽然在表示上非常简单方便,但是也有其缺点,有很大一部分字符用一个字节就可以表示的现在要两个字节表示,存储空间放大了一倍,在现在的网络带宽还非常有限的今天,这样会增大网络传输的流量。
- UTF-8 采用了一种变长技术,每个编码区域有不同的编码长度。不同类型的字符可以是由 1~6 个字节组成。
- UTF-8 有以下编码规则:
- 如果一个字节最高位(第 8 位)为 0,表示这是一个 ASCII 字符(00 - 7F)。可见,所有 ASCII 编码已经是 UTF-8 了。
- 如果一个字节以 11 开头,连续的 1 的个数暗示这个字符的字节数,例如:110xxxxx 代表它是双字节 UTF-8 字符的首字节。
- 如果一个字节,以 10 开始,表示它不是首字节,需要向前查找才能得到当前字符的首字节 。
几种编码的比较
- UTF-16 编码效率最高,字符到字节相互转换更简单,进行字符串操作也更好。
- 它适合在本地磁盘和内存之间使用,可以进行字符和字节之间快速切换,如 Java 的内存编码就是采用 UTF-16 编码。
- 但是它不适合在网络之间传输,因为网络传输容易损坏字节流,一旦字节流损坏将很难恢复。
- 相比较而言 UTF-8 更适合网络传输,对 ASCII 字符采用单字节存储,另外单个字符损坏也不会影响后面其它字符,在编码效率上介于 GBK 和 UTF-16 之间。
- 所以 UTF-8 在编码效率上和编码安全性上做了平衡,是理想的中文编码方式。
编码转换
有了Unicode之后,每一个字符就有了多种不兼容的编码方式,比如说"马"这个字符,它的各种编码方式对应的16进制是:
编码格式 | 16进制 |
---|---|
GB18030 | C2 ED |
Unicode编号 | 9A 6C |
UTF-8 | E9 A9 AC |
UTF-16LE | 6C 9A |
这几种格式之间可以借助Unicode编号进行编码转换。可以简化认为,每种编码都有一个映射表,存储其特有的字符编码和Unicode编号之间的对应关系,这个映射表是一个简化的说法,实际上可能是一个映射或转换方法。
编码转换的具体过程可以是,比如说,一个字符从A编码转到B编码,先找到字符的A编码格式,通过A的映射表找到其Unicode编号,然后通过Unicode编号再查B的映射表,找到字符的B编码格式。
举例来说,"马"从GB18030转到UTF-8,先查GB18030->Unicode编号表,得到其编号是9A 6C,然后查Uncode编号->UTF-8表,得到其UTF-8编码:E9 A9 AC。
与前文提到的切换查看编码方式正好相反,编码转换改变了数据的二进制格式,但并没有改变字符看上去的样子。
3. 乱码产生的原因
首先需要明白的一点是,在计算机并不会真正保存我们输入的汉字的,在计算机中会以字节码的方式保存,再以指定编码输出才是我们所看到的。现在我们来分析一下乱码产生的原因:
以下图示例来说明
上图是以字符串“中文字符+English”为例,在原系统采用utf-8编码的情况下生成了字节码A(具体是多少不重要),再对字节码A采用ASCII解码,就会产生乱码。因为ASCII码的字符集少于UTF-8的字符集,UTF-8的部分字符集不能被ASCII识别,所以会产生乱码。
所以产生乱码的主要原因是文件的编码格式与解码格式不一致或不兼容导致的。知道了原因那怎么解决乱码呢?首先要明白不是所有乱码都是可以恢复的。
在上图中,经ASCII解码后的乱码就已经损失了原字节码值,毕竟UTF-8和ASCII的编码范围就有很大区别。
4. 尝试恢复乱码
如果我们知道文件的编码格式,那么按照编码格式进行解码即可解决。但是很多时候,我们并不知道,可用java程序实现用不同编码测试来恢复。也看使用Notepad++自带的编码格式通过切换使用不同的编码进行尝试来恢复乱码(注意:在切换使用编码时,另备份文件,编码过程是不可逆的)。
public static void recover(String str) throws UnsupportedEncodingException{String[] charsets = new String[]{"windows-1252","GB18030","Big5","UTF-8","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);}}}
}
如文中有任何问题,欢迎指正!
参考链接:
https://www.cnblogs.com/maohuidong/p/8044568.html
https://www.cnblogs.com/swiftma/p/5420145.html
分析乱码产生的原因及常见乱码的解决方法相关推荐
- MySQL的配置方法以及数据库配置常见错误及其解决方法
第一部分.MySQL的配置方法: 以下为笔者整理的mysql 5.5 安装配置教程笔记.通过逐一界面分析,解决大家在配置MySQL数据库时可能存在的疑惑. 首先给出MySQL下载地址:MySQL :: ...
- 值对于int32太大或太小怎么解决_数控车床加工螺纹时常见故障及解决方法
数控技术在线 订单 | 技术 | 干货 | 社群 关注可加入机械行业群! 关注螺纹是在圆柱或圆锥表面上,沿着螺旋线所形成的具有相同剖面和规定牙型的连续凸起和沟槽.在各种机械产品中,带有螺纹的零件应用广 ...
- 康佳电视显示服务器连接异常,康佳电视五大常见故障及解决方法
首页文章列表系统知识正文 康佳电视常见故障--五大常见故障以及解决方法介绍 2016-10-30 22:13:53 16546 电视在使用过程中,也是会经常出现这样那样的问题.康佳电视也不会例外.很 ...
- 数控车床加工螺纹时常见故障及解决方法
螺纹是在圆柱或圆锥表面上,沿着螺旋线所形成的具有相同剖面和规定牙型的连续凸起和沟槽.在各种机械产品中,带有螺纹的零件应用广泛.它主要用作连接零件.紧固零件.传动零件和测量用的零件等等.在数控车床上加工 ...
- 机器学习的5个常见痛点及解决方法
人们可能听说过很多机器学习的用例.例如参加会议.分享人工智能技术的LinkedIn帖子.以及博客文章都有所提及.虽然人们都知道机器学习这个术语,但在多大程度上理解了机器学习的含义? 对于IT或数据科学 ...
- 老男孩教育每日一题-2017年4月28日- MySQL主从复制常见故障及解决方法?
MySQL主从复制常见故障及解决方法? 1.1.1故障1:从库数据与主库冲突 show slave status; 报错:且show slave status\G Slave_I/O_Running: ...
- centos linux 系统日常管理4 scp,rsync,md5sum,sha1sum,strace ,find Rsync 常见错误及解决方法 第十七节课...
centos linux 系统日常管理4 scp,rsync,md5sum,sha1sum,strace ,find Rsync 常见错误及解决方法 第十七节课 rsync可以增量同步,scp不行 ...
- 光纤收发器常见故障及解决方法
光纤收发器一般应用在以太网电缆无法覆盖.必须使用光纤来延长传输距离的实际网络环境中,通常定位于宽带城域网的接入层应用,在各种监控安全工程中应用非常的广泛.但是我们在使用光纤收发器的过程中难免会碰到一些 ...
- java咖啡机故障5_【咖啡小常识】咖啡机不得不知道的常见故障及解决方法
原标题:[咖啡小常识]咖啡机不得不知道的常见故障及解决方法 咖啡行业交流请加私 人微信精品咖啡香,微信号: (长按复制) thinkingcapacity 一.没有蒸汽或做出的咖啡不热 可能原因 1. ...
最新文章
- 7 怎么查看文件夹容量_C盘(系统盘)磁盘剩余容量告警?如何解决与预防,C盘容量告急解决方法简单汇总!...
- AJAX中UPDATEPANEL配合TIMER控件实现局部无刷新
- android jni打印log信息
- 原生js封装table表格操作,获取任意行列td,任意单行单列方法
- 常见的数据增强项目和论文介绍
- QuickPart应用系列
- bestcoder #66
- Linux编辑firmware的文件,Linux中request_firmware 的用法
- 《Algorithms》—— 链表实现栈,队列,背包
- HIVESQL中ROW_NUMBER() OVER语法以及示例
- php redis 菜鸟,安装redis和phpredis模块
- java手机连点脚本_自动点击连点器下载
- PAT乙级1055 集体照
- 【19】processing-硬件(中文)
- 满足功能安全要求的代码测试方案:Parasoft C++test
- pycharm安装netmiko、xlwt
- react钩子_使用钩子在react中分页数据视图
- Ubuntu虚拟机无法与主机复制粘贴文字以及文件解决办法
- 如何系统性学习IT技术
- VMware Workstation 7.1.5 build 491717 精简汉化版
热门文章
- EXCEL---一个简单的查询--对比大佬的方法,学习几个函数 mmult sign find subtitute lookup( , 0/) 等用法
- aba会导致问题_CAS导致的ABA问题及解决
- 爱普生Epson XP-15080 打印机驱动
- 大疆的精灵4 PRO 相机的一些问题
- 秋招攻略—如何成为一名图像算法攻城狮(上篇)—知识学习篇
- 【VMware】安装虚拟机、Linux操作系统
- 使用变电站巡检机器人的两大优势
- 获取UILabel点击的字符LCText
- 微信红包算个毛 ——微信红包,仅仅是个游戏?!
- 在 Mac 上重命名 Apple Magic Mouse的方法!