快捷搜索: 王者荣耀 脱发

Windows-1252字符集(MS1252)造成的困扰

Windows-1252字符集造成的困扰

ISO8859-1与MS1252的差别

Windows-1252字符集是ISO8859-1的超集,与ISO8859-1的唯一不同点在于0x80-0x9F这两页,差别如下图: 注意看两张图的中间,ISO8859-1为空,而Windows-1252有内容,但是0x81,0x8D,0x8F,0x90,0x9D这几个地方是空的,且被标识为不可填充。

MS1252带来的问题

这样会造成的问题是,当一个字节数组被指定使用Windows-1252解码时,字节数组中的0x81,0x8D,0x8F,0x90,0x9D会被转换为?(0x3f),如果你是从网络中接收到的采用UTF-8编码的字节数组,在本地接收并采用Windows-1252解码,如果接收到的字节数组恰好包含上述几个字节,那么我们就没有办法采用Windows-1252解码 - UTF-8编码的方式还原接收到的信息,因为相应字节被永久破坏掉了。 如下代码模拟了这一现象。

String str = new String("华侨永亨银行");
    // 采用UTF-8编码得到字节数组
    byte[] bytes = str.getBytes("UTF-8");
    // bytes: {e5 8d 8e e4 be a8 e6 b0 b8 e4 ba a8 e9 93 b6 e8 a1 8c}
    // 注意第二个字节0x8d,在下面的编解码中被自动转换成了3f

    // 采用Windows-1252解码得到字符串
    str = new String(bytes, "Windows-1252");
    // 采用windows-1252编码,还原字节数组
    bytes = str.getBytes("Windows-1252");
    // bytes: {e5 3f 8e e4 be a8 e6 b0 b8 e4 ba a8 e9 93 b6 e8 a1 8c}

    // 采用UTF-8解码,预期得到原字符串
    str = new String(bytes, "UTF-8");
    // str: ???侨永亨银行,第一个字被永久性破坏

同理也可证明含有另外几个字节0x81,0x8F,0x90,0x9D的字符串也会被破坏。

解决方案

当确定传入的字节中含有上述几个特定的字节时,应该使用ISO8859-1进行接收,当然最后直接使用最终字符集(如这里的UTF-8)。通过实际测试很容易知道,ISO8859-1,没有Windows-1252的情况。

我遇到的情景

采用https协议与服务端进行通讯,按照默认字符集进行接收(默认Windows-1252),由于这是很久以前系统中已经写好的程序,且使用了很久也没有出现问题,恰巧我的需求是接收中文,因此采用的方案是:先按照默认字符集进行接收,拿到字符串后截取指定位置的字符串,按照默认字符集编码成byte,再按照UTF-8解码成中文字符串,解析结果总是会有几个汉字出现乱码的问题。逐步排查才发现有字节被永久性破坏。排查耗时:0.5天

经验分享 程序员 微信小程序 职场和发展