GBK与UTF-8编码错误转换后,无法再正确恢复
字符集错误转换导致的问题
UTF-8格式编码的字节流,按GBK字符集转换为字符串,会出现乱码,这很正常。但将其重新转为字节流,再用UTF-8字符集转为字符串,还是乱码。这就让我产生了疑惑,虽然使用错误的字符集必然导致乱码,但字节的信息并没有改变,因此再转为字节流,用正确的字符集解码,应该得到正常的字符串。但事实是,被错误字符集转换过的字符串,无法恢复到原来的字符集。
问题的根本原因
造成该问题的根源是字节发生了变化。GBK或UTF-8遇到无法解析的字符时,会使用特殊的字符代替,因此造成原有字节信息的丢失,无法恢复。
错误转换的分析
UTF-8 → GBK
对于一串UTF-8编码的字节流,使用GBK进行解码。连续两个大于127的字节被认为是一个GBK编码的字符;若只读到一个大于127的字节,便发生错误,无法解析。此时,用字符'?'代替错误字节,ASCII码是63。
以“樊”字为例,UTF-8编码使用三个字节表示该字符,字节码为[11100110, 10101000, 10001010]([e6, a8, 8a])。使用GBK解码时,读到第一个字节大于127,则取两个字节解析为一个GBK字符。前两个字节e6 8a被解析为GBK字符——妯。 第三个字节无法解析,所以赋值为?,最后的结果是 妯?。
可以看出,最后一个字节的信息丢失了,由8a变成3F,即使把结果再转换为字节流,也无法用utf-8字符集正确解析了。
GBK → UTF-8
对于一串GBK编码的字节流,使用UTF-8解码。UTF-8对于字节的格式有严格要求,当解析某个字符失败时,使用'�'(UTF-8编码为EF BF BD)代替。
继续以“樊”字为例,其GBK字节码为[10110111, 10101110]([B7, AE])。使用UTF-8解码时,根据规则,要求10开头的字节之前,必须有字节标识一个字符的长度,所以两个字节都无法解析。最后的字符串是��。
可以看出,所有的字节信息都丢失了,因此无法再使用GBK解析该字符串。
注意,UTF-8用�替换,是以字符为单位的。例如[11100110, 10101000, 01000001]使用UTF-8解码,得到的结果是�A,而不是��A。根据第一个字节的格式,UTF-8期望将三个字节转换为一个字符。但最后一个字节不符合要求,所以前两个字节被一个�代替。而不是每个字节都被�代替。
GBK与UTF-8编码错误转换后,无法再正确恢复的更多相关文章
- Delphi 编码转换 Unicode gbk big5(使用LCMapString设置区域后,再用API转换)
原文:http://blog.dream4dev.com/article.asp?id=17 function UnicodeEncode(Str: string; CodePage: integer ...
- Lex&Yacc Parser错误发生后再次parser之前恢复初始状态
使用lex yacc 对文件进行parser时,如果文件内容有错,parser报错,然后你修改了文件,再次读入文件进行parser,如果你不是重启程序进行parser,那就需要对做些处理了. &quo ...
- eclipse 解决编译出现GBK或UTF8 编码错误的方法
eclipse由于开源所以支持了比较杂的编码方式,而这些一个工程导入时添加了不少的外来程序,由于不是同一工程一次编码带来了其中含有GBK和 UTF8 UTF16 ASCII等文件编译时就会出现错 ...
- Python_编码错误解决办法 python3 UnicodeEncodeError: 'gbk' codec can't encode character '\xXX' in position XX
先说解决办法:头部加几行代码 import io import sys sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='gb1803 ...
- 关于UTF-8和GBK编码的转换
$oldname=mb_convert_encoding($_POST['oldname'], "GBK" , "UTF-8");//将变量转码为GBK,已知原 ...
- 从Java String实例来理解ANSI、Unicode、BMP、UTF等编码概念
转(http://www.codeceo.com/article/java-string-ansi-unicode-bmp-utf.html#0-tsina-1-10971-397232819ff9a ...
- Code::Blocks开发中的字符串编码错误
刚开始使用Code::Blocks开发Windows中文应用程序的朋友们,如果在代码中使用了中文字符串,编译时可能遇到过Illegal byte sequence或Failure to convert ...
- windows下编译java源文件的编码错误
import java.util.Arrays;public class ArrayAsAReference{ public static void main(String[] args) { int ...
- Python 编码错误的本质原因
转载自:https://foofish.net/python-unicode-error.html 不论你是有着多年经验的 Python 老司机还是刚入门 Python 不久的新贵,你一定遇到过Uni ...
随机推荐
- springboot 常用插件
热部署 使用run as -java application, 把spring-loader-1.2.4.RELEASE.jar下载下来,放到项目的lib目录中,然后把IDEA的run参数里VM参数设 ...
- ruby 数据sql操作
ActiveRecord ActiveRecord 是 Rails 的 ORM 元件,負責與資料庫溝通,讓我們可以用物件導向的語法操作資料庫.在”打造 CRUD 應用程式”一章中提到的對應概念如下: ...
- Ruby中Time的常用函数
Time的常用函数 时间对象. Time.now返回当前时间. 1.Time.at Time.at(time[, usec]) 返回time所指时间的Time对象. time可以是Time对象,也 ...
- SpringMVC 使用 RESTful 架构实现 CRUD 操作
软件152 余建强 源码下载:http://download.csdn.net/detail/qq_35318576/9826210 1 使用框架 SpringMVC.Maven.Ajax.JSTL. ...
- Chrome 谷歌如何快速实现跨域
第一步:在你的E盘或者其他盘新建一个文件夹,命名为:E:\MyChromeDevUserData 第二步:找到你的谷歌浏览器快捷图标,鼠标右键选择属性,出现以下界面: 第三步:在目标选项的最后添加: ...
- s11d27 算法
s11d27 算法 一.理论 1.1 时间复杂度和空间复杂度的理论: 1)空间复杂度: 是程序运行所以需要的额外消耗存储空间,一般的递归算法就要有o(n)的空间复杂度了, 简单说就是递归集算时通常是反 ...
- .net core 2.2 部署CentOS7(5)部署.net core mvc
目录: .net core 2.2 部署CentOS7(1)安装虚拟机 .net core 2.2 部署CentOS7(2)给虚拟机安装CentOS7 .net core 2.2 部署CentOS7( ...
- Java学习-jsp内置对象Session
- Kafka、RabbitMQ、RocketMQ消息中间件的对比
引言 分布式系统中,我们广泛运用消息中间件进行系统间的数据交换,便于异步解耦.现在开源的消息中间件有很多,目前对Kafka.RabbitMQ.RocketMQ这三个消息中间件做下对比分析. - - k ...
- (POI)Excel格式转Html格式
Demo结构和引用的Jar包 源代码(TestDemo.java) POI中将Excel转换为HTML方法仅能转换HSSFWorkBook类型(即03版xls),故可以先将读取的xlsx文件转换成xl ...