初识乱码(上)

一:乱码问题背景

​ window平台下,cocos中,模拟器输出窗口能够输出中文,将日志写入文件时却出现了乱码。

输出中文到模拟器:
输出中文到模拟器
输出中文到文件:​
输出中文到文件

二:问题分析

​ 为什么会乱码?产生乱码的原因无非就两个:

1. 正确的二进制,但用错误的编码读取

​ 这种方式比较简单,转换下编码即可。例如 字GBK二进制为 11001110 11010010,(十六进制表现形式:CE D2),如果这时候用UTF8去读,则是 B

UTF-8编码规则:如果只有一个字节则其最高二进制位为0;如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的字节数,其余各字节均以10开头。UTF-8转换表表示如下:

UTF-8byte数备注
0XXX XXXX1
110X XXXX
10XX XXXX
2
1110XXXX
10XX XXXX
10XX XXXX
3基本定义范围:0~FFFF
1111 0XXX
10XX XXXX
10XX XXXX
10XX XXXX
10XX XXXX
4Unicode6.1定义范围:0~10 FFFF
1111 10XX
10XX XXXX
10XX XXXX
10XX XXXX
10XX XXXX
10XX XXXX
5说明:此非unicode编码范围,属于UCS-4 编码
1111 110X
10XX XXXX
10XX XXXX
10XX XXXX
10XX XXXX
10XX XXXX
10XX XXXX
6说明:此非unicode编码范围,属于UCS-4 编码

​ 根据上面的UTF8编码规则表,和二进制11001110 10010010,我们来看下是怎么读成了B

  • 获取该编码对应的UNICODE编码,11001110 10010010 为两个字节,查找UTF8编码表中byte数为2的格式:

    110X XXXX 10XX XXXX ,对应取出X的位置,01110 010010 不足2个字节,左边补0,UNICODE编码二进制为:0000 0011 1001 0010 (十六进制表现形式:03 92

  • 查UNICOE编码表,可以知道 03 92 对应的是 B
    UNICODE编码表

  • 此时的二进制编码没有被改变,查GBK编码表,CE D2 对应的是 :
    GBK编码表
    总结

    ​ 从上面的分析可以知道,只要二进制不被改变,乱码可通过使用其他编码方式读取进行恢复。

2. 错误的二进制,这时候无论是用什么编码读取都是有问题的

​ 这种方式的乱码就比较难恢复,因为二进制发生了变化,想要恢复到之前的编码,需要进行试错。怎么试错呢?我们分两步来做:

  1. 模拟二进制被改变后产生乱码
  2. 恢复乱码

还是以 字分析,GBK编码 11001110 11010010,(十六进制表现形式:CE D2),如果这个二进制被错误的当成了UTF8,则其二进制码是:11100110 10001000 10010001 3个字节(十六进制表现形式:E6 88 91 ) ,这时用GBK进行读取,11100110 1000100010010001 则无法查到,因为最高位是 1 则表明需要两个字节,那么我们假设分析的是 我我 这时UTF8的二进制是 11100110 10001000 10010001 11100110 10001000 10010001 ,则GBK读取后是 鎴戞垜

分析后可用Python进行验证:

print("我".encode("GBK")) #编码结果 b'\xce\xd2'
print("我".encode("UTF8")) #编码结果 b'\xe6\x88\x91\xe6\x88\x91'
print("我我".encode("UTF8").decode("GBK")) #结果 鎴戞垜

乱码已经模拟出来了,那么如何恢复乱码呢?逆推

print("鎴戞垜".encode("GBK")) #结果 b'\xe6\x88\x91\xe6\x88\x91'
print(binascii.a2b_hex("e68891e68891").decode('utf8')) #结果 我我
#这时候虽然看到的是 我我 ,但其二进制编码仍然是  b'\xe6\x88\x91\xe6\x88\x91'
print("鎴戞垜".encode("GBK").decode("UTF8").encode('GBK')) #结果 b'\xce\xd2'
#这时才是原本的二进制编码,
print("鎴戞垜".encode("GBK").decode("UTF8").encode('GBK').decode('GBK')) #结果 我我

总结

​ 这样乱码就被恢复了,但是这是我们知道了其中间的编码方式,如果我们不知道,怎么办呢?这就是前面说的试错,需要进行中间编码的试错,假设encode是xxx编码,decode是xxx编码,这样一个一个的尝试。那么按这种理论乱码都是可以被恢复的吗?并不是,当二进制数据被破坏了,则乱码不可恢复。

三,解决问题

​ 从上面的分析可以知道,乱码的恢复会有两部分,第一部分,是先改变文本的读取编码方式,这是最方便,也是最快速看到结果的方式;第二部分,中间编码方式的尝试,这种方式比较复杂,而且并不一定能够恢复。很幸运,我的文本乱码属于第一种乱码。

  1. 转换读取编码的工具:notepad++ , UltraEdit
  2. 乱码恢复网站,该网站只是假设中间经过了一层的编码解码而已,但有时会有两层,甚至多层:http://www.mytju.com/classcode/tools/messyCodeRecover.asp

四,问题思考

​ 乱码恢复较为复杂的是第二种方式的乱码,当有中间有多层的编码解码,该如何恢复,能不能做成工具,当有个文本乱码尝试进行恢复?什么情况下乱码又不能恢复呢,如何鉴别?

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值