中文String转utf8,再转回中文

时间:2023-01-10 11:56:20
可以成功转utf8并转回吗?

如果可以的话,
String old = "中文的";
String u8 = new String(old.getBytes("gbk"),"utf-8");
String gb = new String(u8.getBytes("utf-8"),"gbk");
System.out.println(u8);
System.out.println(gb);//会乱码
思路错在哪里

13 个解决方案

#1


不行。
因为对UTF-8合法的字节数组可能对GB不合法,反之也一样。
即,UTF-8和GB不是二进制相容的。

GB和ISO-8859-1可以这样互转,它们是二进制相容的。

#2


refer to this:

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

public class Test {
public static void main(String[] args) {
String str = "测试字符转换 hello word"; //默认环境,已是UTF-8编码
try {
String strGBK = URLEncoder.encode(str, "GBK");
System.out.println(strGBK);
String strUTF8 = URLDecoder.decode(str, "UTF-8");
System.out.println(strUTF8);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}

#3


And:

import java.io.UnsupportedEncodingException;

public class Test {
public static void main(String[] args) throws UnsupportedEncodingException {
String old = "测试字符转换 ";//默认环境,已是UTF-8编码
String gb = new String(old.getBytes("UTF-8"), "GBK");
System.out.println(""+gb); 
String u8 = new String(gb.getBytes("GBK"), "UTF-8");
System.out.println(u8);// 没有乱码
}
}


The results:


娴嬭瘯瀛楃杞崲 
测试字符转换 

#4


引用 1 楼 magong 的回复:
不行。
因为对UTF-8合法的字节数组可能对GB不合法,反之也一样。
即,UTF-8和GB不是二进制相容的。

GB和ISO-8859-1可以这样互转,它们是二进制相容的。


谢高手.
utf8应该包含"中文的"这样的中文吧,虽然编码位置不同于gb。
"UTF-8和GB不是二进制相容",我理解String(old.getBytes("gbk"),"utf-8")是将gbk的二进制转换成utf8相应的二进制,不知理解错在哪

#5



public static void main(String[] args) throws Exception{
String old = "中文的";
String s1 = new String(old.getBytes("gbk"),"iso-8859-1");
String s2 = new String(s1.getBytes("iso-8859-1"),"gbk");
System.out.println(s1);
System.out.println(s2);//中文的
String str = new String(old.getBytes("gbk"),"gbk");
System.out.println(str);//中文的
}

#6


不知道你在问什么。你的代码有任何可能正确的理由值得你来发帖问错在哪里?

#7


说说我的理解吧,java的String在内存中是一直的编码为utf-8的,在你声明了String之后,它在内存中就是utf-8了,你输出至控制台时,虚拟机根据本地的环境编码等因素转化为字节流,然后把这些字节流扔给操作系统,由操作系统负责打印到控制台还是输出至文件

所以我认为lz的转化为字节码之后由转为String,这步实际只是在解码+编码之后,同一存为了utf-8,jvm的内存中的统一编码方式

下面的代码,lz看看,可能有点帮助
String old = "中文的 abcd";

byte [] utf8Decode = old.getBytes("utf-8");
System.out.println("utf8:");
for (byte b: utf8Decode) {
System.out.print(Integer.toHexString(b & 0xFF));
System.out.print(" ");
}
System.out.println();

byte [] gbkDecode = old.getBytes("gbk");
System.out.println("gbk:");
for (byte b: gbkDecode) {
System.out.print(Integer.toHexString(b & 0xFF));
System.out.print(" ");
}
System.out.println();

System.out.println(new String(utf8Decode,"utf-8"));
System.out.println(new String(gbkDecode,"gbk"));


output:
utf8:
e4 b8 ad e6 96 87 e7 9a 84 20 61 62 63 64 
gbk:
d6 d0 ce c4 b5 c4 20 61 62 63 64 
中文的 abcd
中文的 abcd

在这里可以看出utf-8和gbk编码的汉字编码

#8


引用 4 楼 lee0623 的回复:
utf8应该包含"中文的"这样的中文吧,虽然编码位置不同于gb。
"UTF-8和GB不是二进制相容",我理解String(old.getBytes("gbk"),"utf-8")是将gbk的二进制转换成utf8相应的二进制,不知理解错在哪

new String(old.getBytes("gbk"),"utf-8")是将中文字符串的GBK二进制编码 强制认作UTF-8二进制编码,尝试得到中文,当然不会如愿以偿。

#9


在这个帖子的 11 楼中我有详尽的回复,有兴趣的话可以去看看:

求一字符串x
http://topic.csdn.net/u/20080623/16/e0f44f00-eaf9-4d38-b325-a3cc443f2ec9.html

#10


引用 4 楼 lee0623 的回复:
引用 1 楼 magong 的回复:
不行。
因为对UTF-8合法的字节数组可能对GB不合法,反之也一样。
即,UTF-8和GB不是二进制相容的。

GB和ISO-8859-1可以这样互转,它们是二进制相容的。


谢高手.
utf8应该包含"中文的"这样的中文吧,虽然编码位置不同于gb。
"UTF-8和GB不是二进制相容",我理解String(old.getBytes("gb……


简单给你解释下错在哪里.

#11


首先,楼主是知道的,Java中(JVM)字符串、字符 用的是Unicode, 这是Java的标准编码。像'中'用4E2D(16进制)表示。

其次,楼主也知道,世界很大,有很多的语言文字;也知道计算机只识别由0、1组成的代码;这里只说汉字和英文;

美国有个“美国信息交换标准编码”,即ASCII码,ASCII码是英文信息处理的标准编码,用些数字来代表字符,如'A'用数字65表示;

汉字信息处理也必须有一个统一的标准编码,中国是“*国家标准信息交换用汉字编码”,简称“国标”,国标表把七千余汉字、以及标点符号、外文字母等用一些数字来代表,如'中'用5448区位码表示;

这里就是ASCII码表:http://cs.scu.edu.cn/~guobing/c_lan/ppt/ASCII.pdf
这里就是国标区位码表:http://www.xaipe.edu.cn/xwfb/newsfile/20061218120842.doc
Unicode码表请查看官网。

但是处理不同的标准是痛苦的,如汉语,*有一个Big5编码标准,很多编码和国标是相同的,为了解决中文问题,不能从扩展ASCII的角度入手,也不能仅靠中国一家来解决。而必须有一个全新的编码系统,这个系统要可以将中文、英文、法文、德文……等等所有的文字统一起来考虑,为每个文字都分配一个单独的编码,这样才不会有上面那种现象出现。于是,Unicode诞生了。

以上就是我们说的字符集,下面简单说下字符集编码:

Java中Unicode用两个字节表示(UCS-2),但只规定了怎么用多个字节表示各种文字,怎样传输这些编码,这就是由UTF(UCS Transformation Format)规范规定的,常见的UTF规范包括UTF-8、UTF-16等,这就是字符集编码;这里只说UTF-8:
UTF-8用1到6个字节编码UNICODE字符。如果Unicode字符由2个字节表示,则编码成UTF-8很可能需要3个字节,UFT-8转换表表示如下: 
UNICODE        UTF-8
0000 - 007F    0xxxxxxx
0080 - 07FF    110xxxxx 10xxxxxx
0800 - FFFF    1110xxxx 10xxxxxx 10xxxxxx

如'中'的Unicode是 4e2d,显然落在了0800 - FFFF 区,就用三个字节表示:11100100 10111000 10101101; 就是把4e2d转换成2进制0100 1110 0010 1101,依次填入XXX符号就行了。


国标码,全称是GB2312-80, 要理解国标码,楼主得先理解 区位码、国标码与机内码的关系;简单说下:
(1)区位码先转换成十六进制数表示 
(2)区位码(十六进制)+2020H=国标码(十六进制);(两位两位相加) 
(3)国标码(十六进制)+8080H=机内码(十六进制); (两位两位相加)

国标码是不可能在计算机内部直接采用的,与ASCII码发生冲突,如'保' 字,国标码为31H和23H,而西文字符“1”和“#”的SCII也为31H和23H,现假如内存中有两个字节为31H和23H,;这到底是一个汉字,还是两个西文字符“1”;和“#”? 于是就出现了二义性. 
所以是用机内码表示的,其实就是GBK编码,该编码标准兼容GB2312;

还说下区位码的来由:
国标码汉字及符号组成一个94行94列的二维代码表中。在此方阵中,每一行称为一个"区",每一列称为一个"位"。这个方阵实际上组成一个有94个区(编号由01到94),每个区有94个位(编号由01到94)的汉字字符集。每两个字节分别用两位十进制编码,前字节的编码称为区码,后字节的编码称为位码,此即区位码,其中,高两位为区号,低两位为位号。这样区位码可以唯一地确定某一汉字或字符;反之,任何一个汉字或符号都对应一个唯一的区位码,没有重码。

由上面的关系可以知道: 机内码(十六进制) = 区位码(十六进制) + A0A0H;

如'中'的区位码是5448,表示的是'中'在54区,48位,GBK怎样编码呢?如下:
5448的十六进制是3630;
3630 + A0A0 = D6D0;
D6D0就是GBK编码了;

这里有个编码表查询 http://blog.csdn.net/boliu218/archive/2011/01/06/6119710.aspx;

说了这么多,以下不说楼主也基本明白了。

#12


还是说下:
String old = "中文的";//这里在JVM中是Unicode
String u8 = new String(old.getBytes("gbk"),"utf-8");//这里用GBK编码,注意不再是字符串或字符了,是字节,看下GBK编码11010110 11010000 d6d0 11001110 11000100 cec4 10110101 11000100 b5c4, 你解码时用UTF-8,11010110前的110XXXXX告诉解码器是要连续两个字节来解码,问题来了,UTF-8的规范是后一个字节形式是10XXXXXX,可这里是11010000,显然处理不了,这里就要看JVM的实现,我用的是IBM的JDK,他的处理是解码不了就舍弃这两个字节,后面同样处理了。所以返回一个空字符串。
String gb = new String(u8.getBytes("utf-8"),"gbk");//上面返回了个空字符串,这里就没什么编码解码了,gb就是空的。
System.out.println(u8);//无输出
System.out.println(gb);//无数出

如果new String(old.getBytes("gbk"),"utf-8");这一步解码的处理不会发字节丢失或字节替换,后面的new String(u8.getBytes("utf-8"),"gbk");是能成功转回去的,问题是前面的解码中UTF-8能表示出GBK的编码,哪怕是我们说的乱码。

#13


谢谢各位,特别是
magong 
(行者67685C1196C4) 

bao110908
()火龙果() 

结帖.

#1


不行。
因为对UTF-8合法的字节数组可能对GB不合法,反之也一样。
即,UTF-8和GB不是二进制相容的。

GB和ISO-8859-1可以这样互转,它们是二进制相容的。

#2


refer to this:

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

public class Test {
public static void main(String[] args) {
String str = "测试字符转换 hello word"; //默认环境,已是UTF-8编码
try {
String strGBK = URLEncoder.encode(str, "GBK");
System.out.println(strGBK);
String strUTF8 = URLDecoder.decode(str, "UTF-8");
System.out.println(strUTF8);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}

#3


And:

import java.io.UnsupportedEncodingException;

public class Test {
public static void main(String[] args) throws UnsupportedEncodingException {
String old = "测试字符转换 ";//默认环境,已是UTF-8编码
String gb = new String(old.getBytes("UTF-8"), "GBK");
System.out.println(""+gb); 
String u8 = new String(gb.getBytes("GBK"), "UTF-8");
System.out.println(u8);// 没有乱码
}
}


The results:


娴嬭瘯瀛楃杞崲 
测试字符转换 

#4


引用 1 楼 magong 的回复:
不行。
因为对UTF-8合法的字节数组可能对GB不合法,反之也一样。
即,UTF-8和GB不是二进制相容的。

GB和ISO-8859-1可以这样互转,它们是二进制相容的。


谢高手.
utf8应该包含"中文的"这样的中文吧,虽然编码位置不同于gb。
"UTF-8和GB不是二进制相容",我理解String(old.getBytes("gbk"),"utf-8")是将gbk的二进制转换成utf8相应的二进制,不知理解错在哪

#5



public static void main(String[] args) throws Exception{
String old = "中文的";
String s1 = new String(old.getBytes("gbk"),"iso-8859-1");
String s2 = new String(s1.getBytes("iso-8859-1"),"gbk");
System.out.println(s1);
System.out.println(s2);//中文的
String str = new String(old.getBytes("gbk"),"gbk");
System.out.println(str);//中文的
}

#6


不知道你在问什么。你的代码有任何可能正确的理由值得你来发帖问错在哪里?

#7


说说我的理解吧,java的String在内存中是一直的编码为utf-8的,在你声明了String之后,它在内存中就是utf-8了,你输出至控制台时,虚拟机根据本地的环境编码等因素转化为字节流,然后把这些字节流扔给操作系统,由操作系统负责打印到控制台还是输出至文件

所以我认为lz的转化为字节码之后由转为String,这步实际只是在解码+编码之后,同一存为了utf-8,jvm的内存中的统一编码方式

下面的代码,lz看看,可能有点帮助
String old = "中文的 abcd";

byte [] utf8Decode = old.getBytes("utf-8");
System.out.println("utf8:");
for (byte b: utf8Decode) {
System.out.print(Integer.toHexString(b & 0xFF));
System.out.print(" ");
}
System.out.println();

byte [] gbkDecode = old.getBytes("gbk");
System.out.println("gbk:");
for (byte b: gbkDecode) {
System.out.print(Integer.toHexString(b & 0xFF));
System.out.print(" ");
}
System.out.println();

System.out.println(new String(utf8Decode,"utf-8"));
System.out.println(new String(gbkDecode,"gbk"));


output:
utf8:
e4 b8 ad e6 96 87 e7 9a 84 20 61 62 63 64 
gbk:
d6 d0 ce c4 b5 c4 20 61 62 63 64 
中文的 abcd
中文的 abcd

在这里可以看出utf-8和gbk编码的汉字编码

#8


引用 4 楼 lee0623 的回复:
utf8应该包含"中文的"这样的中文吧,虽然编码位置不同于gb。
"UTF-8和GB不是二进制相容",我理解String(old.getBytes("gbk"),"utf-8")是将gbk的二进制转换成utf8相应的二进制,不知理解错在哪

new String(old.getBytes("gbk"),"utf-8")是将中文字符串的GBK二进制编码 强制认作UTF-8二进制编码,尝试得到中文,当然不会如愿以偿。

#9


在这个帖子的 11 楼中我有详尽的回复,有兴趣的话可以去看看:

求一字符串x
http://topic.csdn.net/u/20080623/16/e0f44f00-eaf9-4d38-b325-a3cc443f2ec9.html

#10


引用 4 楼 lee0623 的回复:
引用 1 楼 magong 的回复:
不行。
因为对UTF-8合法的字节数组可能对GB不合法,反之也一样。
即,UTF-8和GB不是二进制相容的。

GB和ISO-8859-1可以这样互转,它们是二进制相容的。


谢高手.
utf8应该包含"中文的"这样的中文吧,虽然编码位置不同于gb。
"UTF-8和GB不是二进制相容",我理解String(old.getBytes("gb……


简单给你解释下错在哪里.

#11


首先,楼主是知道的,Java中(JVM)字符串、字符 用的是Unicode, 这是Java的标准编码。像'中'用4E2D(16进制)表示。

其次,楼主也知道,世界很大,有很多的语言文字;也知道计算机只识别由0、1组成的代码;这里只说汉字和英文;

美国有个“美国信息交换标准编码”,即ASCII码,ASCII码是英文信息处理的标准编码,用些数字来代表字符,如'A'用数字65表示;

汉字信息处理也必须有一个统一的标准编码,中国是“*国家标准信息交换用汉字编码”,简称“国标”,国标表把七千余汉字、以及标点符号、外文字母等用一些数字来代表,如'中'用5448区位码表示;

这里就是ASCII码表:http://cs.scu.edu.cn/~guobing/c_lan/ppt/ASCII.pdf
这里就是国标区位码表:http://www.xaipe.edu.cn/xwfb/newsfile/20061218120842.doc
Unicode码表请查看官网。

但是处理不同的标准是痛苦的,如汉语,*有一个Big5编码标准,很多编码和国标是相同的,为了解决中文问题,不能从扩展ASCII的角度入手,也不能仅靠中国一家来解决。而必须有一个全新的编码系统,这个系统要可以将中文、英文、法文、德文……等等所有的文字统一起来考虑,为每个文字都分配一个单独的编码,这样才不会有上面那种现象出现。于是,Unicode诞生了。

以上就是我们说的字符集,下面简单说下字符集编码:

Java中Unicode用两个字节表示(UCS-2),但只规定了怎么用多个字节表示各种文字,怎样传输这些编码,这就是由UTF(UCS Transformation Format)规范规定的,常见的UTF规范包括UTF-8、UTF-16等,这就是字符集编码;这里只说UTF-8:
UTF-8用1到6个字节编码UNICODE字符。如果Unicode字符由2个字节表示,则编码成UTF-8很可能需要3个字节,UFT-8转换表表示如下: 
UNICODE        UTF-8
0000 - 007F    0xxxxxxx
0080 - 07FF    110xxxxx 10xxxxxx
0800 - FFFF    1110xxxx 10xxxxxx 10xxxxxx

如'中'的Unicode是 4e2d,显然落在了0800 - FFFF 区,就用三个字节表示:11100100 10111000 10101101; 就是把4e2d转换成2进制0100 1110 0010 1101,依次填入XXX符号就行了。


国标码,全称是GB2312-80, 要理解国标码,楼主得先理解 区位码、国标码与机内码的关系;简单说下:
(1)区位码先转换成十六进制数表示 
(2)区位码(十六进制)+2020H=国标码(十六进制);(两位两位相加) 
(3)国标码(十六进制)+8080H=机内码(十六进制); (两位两位相加)

国标码是不可能在计算机内部直接采用的,与ASCII码发生冲突,如'保' 字,国标码为31H和23H,而西文字符“1”和“#”的SCII也为31H和23H,现假如内存中有两个字节为31H和23H,;这到底是一个汉字,还是两个西文字符“1”;和“#”? 于是就出现了二义性. 
所以是用机内码表示的,其实就是GBK编码,该编码标准兼容GB2312;

还说下区位码的来由:
国标码汉字及符号组成一个94行94列的二维代码表中。在此方阵中,每一行称为一个"区",每一列称为一个"位"。这个方阵实际上组成一个有94个区(编号由01到94),每个区有94个位(编号由01到94)的汉字字符集。每两个字节分别用两位十进制编码,前字节的编码称为区码,后字节的编码称为位码,此即区位码,其中,高两位为区号,低两位为位号。这样区位码可以唯一地确定某一汉字或字符;反之,任何一个汉字或符号都对应一个唯一的区位码,没有重码。

由上面的关系可以知道: 机内码(十六进制) = 区位码(十六进制) + A0A0H;

如'中'的区位码是5448,表示的是'中'在54区,48位,GBK怎样编码呢?如下:
5448的十六进制是3630;
3630 + A0A0 = D6D0;
D6D0就是GBK编码了;

这里有个编码表查询 http://blog.csdn.net/boliu218/archive/2011/01/06/6119710.aspx;

说了这么多,以下不说楼主也基本明白了。

#12


还是说下:
String old = "中文的";//这里在JVM中是Unicode
String u8 = new String(old.getBytes("gbk"),"utf-8");//这里用GBK编码,注意不再是字符串或字符了,是字节,看下GBK编码11010110 11010000 d6d0 11001110 11000100 cec4 10110101 11000100 b5c4, 你解码时用UTF-8,11010110前的110XXXXX告诉解码器是要连续两个字节来解码,问题来了,UTF-8的规范是后一个字节形式是10XXXXXX,可这里是11010000,显然处理不了,这里就要看JVM的实现,我用的是IBM的JDK,他的处理是解码不了就舍弃这两个字节,后面同样处理了。所以返回一个空字符串。
String gb = new String(u8.getBytes("utf-8"),"gbk");//上面返回了个空字符串,这里就没什么编码解码了,gb就是空的。
System.out.println(u8);//无输出
System.out.println(gb);//无数出

如果new String(old.getBytes("gbk"),"utf-8");这一步解码的处理不会发字节丢失或字节替换,后面的new String(u8.getBytes("utf-8"),"gbk");是能成功转回去的,问题是前面的解码中UTF-8能表示出GBK的编码,哪怕是我们说的乱码。

#13


谢谢各位,特别是
magong 
(行者67685C1196C4) 

bao110908
()火龙果() 

结帖.