Excel表格网

为什么改了gbk还是乱码?

251 2024-03-15 14:36 admin   手机版

一、为什么改了gbk还是乱码?

我们知道在计算机内存中,存储的是二进制数据,在网络传输中,也是二进制数据,但最终呈现给用户的是字符串,二进制与字符串的转化就需要编码、解码的参与,如果世界上只有一种字符编码方式,就不会有乱码这一说了,但事实是,编码的方式太多了,utf-8、utf-32、utf-16、gbk、gb2312、iso-8859-1、big5、unicode等等。由于每个编码的规则不一样,一般都不能用一种进行编码,用另一种进行解码。如utf-8中,一个字母用一个字节表示,一个汉字用三个字节表示,特殊的汉字用四个字节表示,而gbk中,一个字母用一个字节表示,一个汉字用两个字节表示。

有一个说法,内存中存储的二进制是unicode码,如果内存中的数据需要存储或传输时,才会进行一次转化,将unicode码转化成其它的编码二进制(有待考证)。个人觉得这种方式很合理,毕竟unicode码中每个字符都有独一无二的二进制与之对应。

排查乱码问题,难度在于是在哪个环节出了问题,但乱码的本质都是一样的,读取二进制的编码和最初将字符串转化成二进制的编码方式不一致。

此处说明一个概念,编码指将字符串转化成二进制,解码指将二进制转化成字符串。

UTF-8编码,GBK解码

在这我们讨论一下,gbk和utf-8互转的乱码问题,直接上代码。

package com.anjz.test;

import java.io.UnsupportedEncodingException;

public class CodingTest {

public static void main(String[] args) throws UnsupportedEncodingException {

String str = "你好,世界";

System.out.println("字符串长度:"+str.length());

byte[] utfBytes = str.getBytes("utf-8");

System.out.println("utf-8需要"+utfBytes.length+"字节存储");

byte[] gbkBytes = str.getBytes("gbk");

System.out.println("gbk需要"+gbkBytes.length+"字节存储");

}

}

以上代码运行打印出一下内容:

字符串长度:5

utf-8需要15字节存储

gbk需要10字节存储

可以看出,utf-8存储一个汉字,需要3个字节,gbk存储一个汉字,需要2个字节。

现用单个字符测试。

package com.anjz.test;

import java.io.UnsupportedEncodingException;

public class CodingTest {

public static void main(String[] args) throws UnsupportedEncodingException {

String str = "你";

byte[] utfBytes = str.getBytes("utf-8");

for(byte utfByte:utfBytes){

//字节对应的十进制是负数,因java中的二进制使用补码表示的,此处使用0xff 还原成int表示的数据,再转化成16进制

System.out.print(Integer.toHexString((utfByte & 0xFF)) +",");

}

System.out.println();

String utf2gbkStr = new String(str.getBytes("utf-8"),"gbk");

System.out.println("utf-8转化成gbk:"+utf2gbkStr);

byte[] gbkBytes = utf2gbkStr.getBytes("gbk");

for(byte gbkByte:gbkBytes){

System.out.print(Integer.toHexString((gbkByte & 0xFF))+",");

}

System.out.println();

String gbk2utfStr = new String(utf2gbkStr.getBytes("gbk"),"utf-8");

System.out.println("gbk转化成utf-8:"+gbk2utfStr);

}

}

运行上面代码,得出的结果:

e4,bd,a0,

utf-8转化成gbk:浣�

e4,bd,3f,

gbk转化成utf-8:�?

用两个字符测试,将上述代码String str = “你”改成String str = “你好”。运行代码,得出的结果:

e4,bd,a0,e5,a5,bd,

utf-8转化成gbk:浣犲ソ

e4,bd,a0,e5,a5,bd,

gbk转化成utf-8:你好

上述实验中,utf-8转化成gbk出现乱码,这个很好理解,但是再还原回去,gbk转化成utf-8,单个中文字符依然是乱码,两个字符却能正常显示,这个到底是怎么回事呢?

经过一番研究,想把这个事说明白,还需要从它们的编码规则着手。

ISO-8859-1

单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。

GBK

采用单双字节变长编码,英文使用单字节编码,完全兼容ASCII字符编码,中文部分采用双字节编码。双字节其编码范围从8140至FEFE(剔除xx7F)。

单字节:00000000 - 01111111

双字节:10000001 01000000 - 11111110 11111110 (剔除******** 01111111)

单字节、双字节的区分通过高字节高位区分,单字节高位为0,双字节的高字节高位为1。

UTF-8

可变长字符编码,是unicode码的具体实现,UTF-8用1到6个字节编码Unicode字符。

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

1字节 0xxxxxxx

2字节 110xxxxx 10xxxxxx

3字节 1110xxxx 10xxxxxx 10xxxxxx

4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

明白上述GBK和UTF-8的编码规则,我们再分析一下,单个中文字符是乱码,两个字符却能正常显示的问题。

“你”

UTF-8编码对应的二进制:11100100 10111101 10100000

将上述二进制通过GBK进行解码,根据GBK规则,第一个字节高位为1,使用双字节编码,

“11100100 10111101”解码成“浣”,“10100000”对于GBK来说是非法的,就解码成了一种特殊字符“�”。

看看能不能将“浣�”还原回“你”呢?

GBK编码对应的二进制:11100100 10111101 00111111

看到上述的二进制,根本不符合UTF-8编码规则,故用UTF-8进行解码,是解码成了一些特殊字符“�?”。

对于上述情况可以看出,一个二进制,如果不符合当前的编码规则,会被解码成特殊字符,但此特殊字符再进行编码,是回不到最初的二进制的。

 

用同样的方式,分析“你好”为什么最终可以正常显示。

UTF-8编码对应的二进制:11100100 10111101 10100000 11100101 10100101 10111101

将上述二进制通过GBK进行编码,根据GBK规则,使用双字节编码,“1100100 10111101”解码成“浣”,“10100000 11100101”解码成“犲”,“10100101 10111101”解码成“ソ”。

看看能不能将“浣犲ソ”还原成“你好”呢?

GBK 编码对应的二进制:11100100 10111101 10100000 11100101 10100101 10111101

可以看出二进制是可以被还原的,将此二进制通过UTF-8解码,肯定能变成“你好”。

 

可以看出,一个字符串,通过UTF-8进行编码,再通过GBK进行解码,再将得到的字符串进行GBK编码,最后将得到的二进制通过UTF-8解码,能否还原到最初的字符串,在于UTF-8编码后得到的二进制,是否符合GBK的编码规则,如果符合,最终就可以还原,如果不符合,就不可还原。

GBK编码,UTF-8解码

package com.anjz.test;

import java.io.UnsupportedEncodingException;

public class CodingTest {

public static void main(String[] args) throws UnsupportedEncodingException {

String str = "你好";

byte[] gbkBytes = str.getBytes("gbk");

for(byte gbkByte:gbkBytes){

//字节对应的十进制是负数,因java中的二进制使用补码表示的,此处使用0xff 还原成int表示的数据,再转化成16进制

System.out.print(Integer.toHexString((gbkByte & 0xFF)) +",");

}

System.out.println();

String gbk2utfStr = new String(str.getBytes("gbk"),"utf-8");

System.out.println("gbk转化成utf-8:"+gbk2utfStr);

byte[] utfBytes = gbk2utfStr.getBytes("utf-8");

for(byte utfByte:utfBytes){

System.out.print(Integer.toHexString((utfByte & 0xFF))+",");

}

System.out.println();

String utf2gbkStr = new String(gbk2utfStr.getBytes("utf-8"),"gbk");

System.out.println("utf-8转化成gbk:"+utf2gbkStr);

}

}

运行上述代码,结果为:

c4,e3,ba,c3,

gbk转化成utf-8:���

ef,bf,bd,ef,bf,bd,ef,bf,bd,

utf-8转化成gbk:锟斤拷锟�

上述结果应该都在意料之中,我们通过上述的方法分析一下。

“你好”GBK编码的二进制:11000100 11100011 10111010 11000011

GBK编码的二进制数据,完全匹配不了UTF-8的编码规则,最终UTF-8只能按如下方式匹配,查看第一个字节,开头“110”,理论上匹配两个字节,但看下一个字节,开头却不是“10”,最终“11000100”解码成“�”,看第二个字节开头是“1110”,理论匹配三个字节,看下个字节符合,以“10”开头,但下下个字节开头是“110”,不符合匹配,最终“11100011 10111010”解码成“�”,同理“11000011”也解码成“�”,这个符号都是为找不到对应规则随意匹配的一个特殊字符。

“���”UTF-8编码的二进制为:11101111 10111111 10111101 11101111 10111111 10111101 11101111 10111111 10111101

这个二进制和原先的二进制不相同,根本转化不到最初的字符串,按照GBK的编码规则,“11101111 10111111”编码成“锟”,“10111101 11101111” 编码成“斤”,“10111111 10111101”编码成“拷”,“11101111 10111111”编码成“锟”,“10111101”不符合GBK规则,编码成特殊字符“�”。

理论上说,用GBK编码,UTF-8解码的字符串是不能还原到最初的字符串的,因UTF-8编码规则的特殊性,GBK编出的二进制,是很难匹配上的。

总结

理论上说,系统出现乱码,将乱码还原到最初的样子,上述UTF-8编码,GBK解码,这个有时是可以还原的,有时是还原不了的,要看UTF-8编码的二进制是否都能符合GBK的编码规则,但GBK编码,UTF-8解码,这个基本是条不归路。

但实际中,有一种情况,是100%可以将乱码还原成最初的字符串。就是任意编码格式编码,ISO-8859-1解码,这个主要因为ISO-8859-1是单字节编码,而且匹配所有单字节情况,乱码字符串总是可以还原到最初的二

二、c语言乱码怎么解决?

1.字符串数组各字符单个赋值的话,在每串最后一个字符之后添加 '\0',表示串结束了,输入时就没有多余的乱码了,因为gets()或scanf() 的%s都是主动在串结束后添加了 '\0'的。

2.字符串使用前请使用清空语句把垃圾内存清理成'\0',也就是0x00(0):

三、excel修改了单元格式后还是乱码怎么回事?

如果在Excel中修改了单元格的格式后仍然出现乱码,可能是以下几个原因导致的:

1. 字体不兼容:如果为单元格选择了某种特殊的字体,而该字体在其他设备上可能并没有安装,或者Excel本身不支持该字体,那么就会导致乱码。尝试更换为常用的字体,如Arial或Times New Roman,看看是否解决了问题。

2. 字符编码不匹配:Excel使用的字符编码格式可能与你当前所使用的系统或文本编码格式不一致,导致乱码。可以尝试更改Excel的字符编码设置,使其与你的系统或文本编码一致。

3. 文本格式错误:如果将本应该是数值的数据格式化为文本后,可能会导致数字显示为乱码。尝试将数据格式设置回数值格式,看看是否解决了问题。

4. 数据源字符集问题:如果从其他来源(如数据库、文本文件等)导入数据到Excel中时出现乱码,可能是由于数据源的字符集与Excel不兼容。在导入数据时,可以尝试调整字符集设置,确保与数据源一致。

5. 文件损坏:如果文件本身存在损坏或损坏部分,可能会导致乱码。尝试打开其他的Excel文件,看看是否也会出现乱码问题。如果其他文件正常,那么可能是当前文件损坏,可以尝试使用Excel的修复功能修复文件。

如果以上方法都没有解决乱码问题,建议备份文件后重新打开Excel,或者尝试在其他计算机上打开文件,查看是否仍然存在乱码。如果问题依然存在,可能需要考虑咨询专业的技术支持人员来进一步解决问题。

四、WOW系统字体乱码?

如果WOW系统出现字体乱码的问题,可能是由于字体文件损坏或缺失导致的。您可以尝试以下解决方法:1.重新安装WOW游戏,确保安装过程中没有出现错误。2.检查您的操作系统字体文件是否完整,如果有损坏或缺失的字体文件,可以尝试修复或重新安装字体。3.更新显卡驱动程序,确保显卡驱动程序与WOW游戏兼容。4.在WOW游戏设置中,尝试更改字体设置,选择一个可用的字体。如果问题仍然存在,建议您联系WOW游戏的技术支持团队,寻求进一步的帮助和指导。

五、系统乱码怎样恢复?

1、点击开始按钮,然后点击“控制面板”

2、先将“查看方式”设置成“类别”,然后点击“时钟、语言和区域”

3、再点击“区域和语言”

4、点击“管理”选项卡,然后点击“更改系统区域设置”

5、将“当前系统区域设置”设置成“英语”,然后点击确定按钮,重启电脑。重启电脑后整个系统通常会全部变成乱码。

6、重启电脑后,再次找到上面那个位置,将“当前系统区域设置”设置成“中文简体”,点击确定按钮,重启电脑。

六、php各种语言乱码

在网站开发中,PHP 是一种非常常用的编程语言,但在处理各种语言乱码时可能会遇到一些问题。PHP 作为一种服务器端脚本语言,通常与数据库一起使用,可以处理表单数据、生成动态页面、发送和接收 cookies 以及处理 session 管理等功能。

乱码问题

当网站涉及多语言内容时,特别是中文、日文、韩文等非拉丁语系的语言时,就会出现乱码问题。造成乱码的原因通常包括字符集不匹配、编码不一致、服务器配置问题等。在 PHP 开发中,解决乱码问题需要一定的技术和经验。

字符集和编码

为了避免乱码问题,开发人员首先需要了解字符集和编码的概念。字符集是一个字符集合,比如 Unicode,而编码则是将字符集中的字符编码成字节序列的规则,比如 UTF-8、GBK、Big5 等。在 PHP 中,可以通过设置 header 来指定页面的字符集编码,比如:

<?php header('Content-Type: text/html; charset=utf-8'); ?>

这样可以确保页面以 UTF-8 编码进行显示,避免乱码问题的发生。另外,在处理数据库连接时,也需要确保数据库的字符集和 PHP 脚本的字符集保持一致,以免出现乱码。

PHP 处理乱码

在 PHP 中处理乱码问题的方式多种多样,可以根据具体情况选择合适的方法。一种常见的处理方法是使用 PHP 内置的函数对字符串进行编码转换,比如:

<?php
$text = '中文内容';
echo mb_convert_encoding($text, 'UTF-8', 'auto');
?>

这样可以将内容转换为 UTF-8 编码,避免乱码显示。另外,还可以通过设置数据库连接的字符集,使用 htmlspecialchars 处理用户输入数据等方式来规避乱码问题。

其他语言乱码处理

除了中文字符集问题外,还有一些其他语言可能会遇到乱码问题,比如日文、韩文等。对于这些语言,开发人员需要了解其特定的字符集和编码规则,以便正确处理乱码。

在处理日文乱码时,可以使用 mb_convert_encoding 函数将 Shift_JIS 编码的日文内容转换为 UTF-8 编码,以确保在页面中正确显示。而对于韩文,通常采用 EUC-KR 或 UTF-8 编码来处理乱码问题。

结语

综上所述,PHP 在处理各种语言乱码时需要注意字符集和编码的匹配,确保页面和数据库的字符集设置一致,适时使用 PHP 内置函数进行编码转换等操作,以避免出现乱码显示的情况。只有在细致处理乱码问题的同时,才能确保网站内容以清晰、准确的形式呈现给用户,提升用户体验。

七、c语言乱码怎么改?

c语言的乱码通常是由于编码格式不匹配或者输出方式不正确所导致的。要解决这个问题,首先要确认使用的编码格式和程序中的字符集是否一致,比如在写入文件或者输出到终端时要使用相同的编码格式。其次,要注意在读写文件、输入输出等操作中使用正确的字符编码。另外,也要留意程序中字符串的处理和转换,确保不会出现乱码。总之,解决C语言乱码问题需要细心排查程序中的各个环节,保证字符集和编码格式的一致性。

八、c语言输出数字是乱码?

c语言输出乱码,多半是因为格式字符串设置错误。如:x=22;printf("%c",x); 就会输出乱码。

九、c语言输出乱码怎么解决?

1.字符串数组各字符单个赋值的话,在每串最后一个字符之后添加 '\0',表示串结束了,输入时就没有多余的乱码了,因为gets()或scanf() 的%s都是主动在串结束后添加了 '\0'的。

2.字符串使用前请使用清空语句把垃圾内存清理成'\0',也就是0x00(0):

十、Linux选择中文语言却是乱码?

如果Linux选择中文语言却是乱码表现为网络无法连接,原因和解决方法如下三、欠费

如果手机欠费了,那么就无法使用移动数据网络,国内三大通信运营商提供预付费和后付费两种付费模式,大多数用户使用的都是预付费模式,一旦发生欠费,会在24小时之内进入单停状态,此时的手机只能接听电话、收短信,不能打电话、发短信,也不能使用移动数据网络。

遇到这种情况,将欠费缴清,然后尝试开启移动数据网络,如果仍然不好使,直接重启下手机就可以正常使用了。

顶一下
(0)
0%
踩一下
(0)
0%
相关评论
我要评论
用户名: 验证码:点击我更换图片