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期望将三个字节转换为一个字符。但最后一个字节不符合要求,所以前两个字节被一个?代替。而不是每个字节都被?代替。

原文地址:https://www.cnblogs.com/DataArt/p/10010878.html

时间: 2024-11-11 11:54:47

GBK与UTF-8编码错误转换后,无法再正确恢复的相关文章

Delphi 编码转换 Unicode gbk big5(使用LCMapString设置区域后,再用API转换)

原文:http://blog.dream4dev.com/article.asp?id=17 function UnicodeEncode(Str: string; CodePage: integer): WideString;var Len: integer;begin Len := Length(Str) + 1; SetLength(Result, Len); Len := MultiByteToWideChar(CodePage, 0, PChar(Str), -1, PWideChar

javac编译出现的编码错误: 编码GBK的不可映射字符

在Windows平台下,当Java源代码中包含中文字符时,如果我们利用代码编辑器保存代码时是utf-8编码格式保存,那么我们在用javac编译时会出现“错误:编码GBK的不可映射字符”. 我们在用javac编译时,编译程序首先会获得我们windows操作系统默认采用的编码格式(GBK),这样在从硬盘读取java文件的时候就相当于按GBK格式解码进内存中,而原编码为utf-8,就会发生解码错误,导致无法编译.当我们不加设置就编译时,相当于使用了参数:javac -encoding GBK Stre

编程实现GBK到UFT-8编码的转换

/iconv_linux下字符集编码转换轻松实现 (1) iconv_t iconv_open(const char *tocode, const char *fromcode); //此函数说明将要进行哪两种编码的转换,tocode是目标编码,fromcode是原编码,该函数返回一个转换句柄,供以下两个函数使用. (2) size_t iconv(iconv_t cd,char **inbuf,size_t *inbytesleft,char **outbuf,size_t *outbytes

正确理解和使用GBK及UTF-8网页编码

网页编码英文译为web page encoding,是在网页中指定其特定的字符编码格式的库. GBK是国家标准GB2312基础上扩容后兼容GB2312的标准.GBK的文字编码是用双字节来表示的,即不论中.英文字符均使用双字节来表示,为了区分中文,将其最高位都设定成1.GBK包含全部中文字符,是国家编码,通用性比UTF8差,不过UTF8占用的数据库比GBK大. UTF-8:Unicode TransformationFormat-8bit,允许含BOM,但通常不含BOM.是用以解决国际上字符的一种

PHP 字符串编码的转换

原文链接:http://mangguo.org/php-string-encoding-convert-and-detect/ GBK 和 UTF-8 编码的转换是一个非常恶心的事情,比如像 PHP 中的 json_encode 本身根本不支持 GBK 形式的编码.有两个库函数能够支持编码的转换,通常能够想到的就是 iconv 函数,使用起来也非常爽: iconv('GBK', 'UTF-8//IGNORE', '芒果小站'); // 将字符串由 GBK 编码转换为 UTF-8 编码 但 ico

Linux下将UTF8编码批量转换成GB2312编码的方法

Linux下将UTF8编码批量转换成GB2312编码的方法 在sqlplus中导入UTF8编码的sql脚本就会出现乱码错误,这时就需要将UTF8编码转换成GB2312编码,下面为大家介绍下在Linux下如何进行转换 UTF8编码和GB2312编码是有区别的,在sqlplus中导入UTF8编码的sql脚本就会出现乱码错误,这时就需要将UTF8编码转换 成GB2312编码,可是一个个的转换十分麻烦,下面小编就教你如何在Linux下将UTF8编码批量转换成GB2312编码. 背景 本人在使用oracl

Python文件读取编码错误问题解决之(PyCharm开发工具默认设置的坑。。。)

刚接触Python学习,正准备做个爬虫的例子,谁知道代码一开始就遇到了一个大坑,狂汗啊. 问题是这样的:我通过代码爬取了博客园首页的HTML代码并存入到blog.txt文件当中,然后准备读取出来之后进行分析,可就在读取文件的这一步出现了问题. 执行读取代码的时候程序总是会抛一个叫 “UnicodeEncodeError: 'gbk' codec can't encode character '\xbb' in position 117274: illegal multibyte sequence

关于Apache默认编码错误,导致网站乱码的解决方案

最近经常有同学在使用LAMP/WAMP时,遇到这样的编码错误问题: A网站程序编码UTF-8编码安装成功,运行成功. B网站程序编gb2312也要安装在同一服务器上. 这样就出现问题了,Apache默认编码UTF-8在解析A网站的时候没有任何问题,当运行B网站时出现的"蝌蚪文"乱码问题. 单纯的修改Apache默认编码为gb2312这样就导致A网站出现"蝌蚪文". 问题分析: 如果你在网上搜索 “apache配置”,搜到的页面大多都会建议你在httpd.conf中加

3 -11 字符编码与转换

中文的字符编码  是 gbk   windows 默认的字符编码也是gbk 每个国家都有自己的字符编码 为了 统一 就有了 unicode ##unicode 不管英文中文都占 2个字节  16位 ascii码 一个英文一个字节  不能存中文.. 8 位 英文 或特殊字符 转换后 中文 变成3个字节 其中utf-8 是  Unicode的 可变长度的扩展级  encode 是编码    decode  是 解码    import sysprint(sys.getdefaultencoding(