将字符串从一个字符集转换为另一个字符集

Arp*_*wal 0 java ascii character-encoding ebcdic

我正在努力将字符串从一个字符集转换为另一个字符串,并在其上阅读许多示例,最后找到下面的代码,这对我来说很好,作为Charset Encoding的新手,我想知道,如果这是正确的方法它.

public static byte[] transcodeField(byte[] source, Charset from, Charset to) {
    return new String(source, from).getBytes(to);
} 
Run Code Online (Sandbox Code Playgroud)

要将String从ASCII转换为EBCDIC,我必须这样做:

System.out.println(new String(transcodeField(ebytes,
                Charset.forName("US-ASCII"), Charset.forName("Cp1047"))));
Run Code Online (Sandbox Code Playgroud)

要从EBCDIC转换为ASCII,我必须这样做:

System.out.println(new String(transcodeField(ebytes,
                Charset.forName("Cp1047"), Charset.forName("US-ASCII"))));
Run Code Online (Sandbox Code Playgroud)

Kay*_*man 10

您找到的代码(transcodeField)不会将String一种编码转换为另一种编码,因为String它没有编码¹.它将字节从一种编码转换为另一种编码.该方法仅在您的用例满足2个条件时才有用:

  1. 您的输入数据是字节
  2. 您的输出数据需要是字节

在这种情况下,它是直截了当的:

byte[] out = transcodeField(inbytes, Charset.forName(inEnc), Charset.forName(outEnc));
Run Code Online (Sandbox Code Playgroud)

如果输入数据包含无法在输出编码中表示的字符(例如将复数转换UTF8ASCII),则这些字符将替换为?替换符号,并且数据将被破坏.

然而,很多人问" 我如何将字符串从一种编码转换为另一种编码 ",很多人用以下代码回答:

String s = new String(source.getBytes(inputEncoding), outputEncoding);

这是完全公牛****.该getBytes(String encoding)方法返回一个字节数组,其中包含以指定编码编码的字符(如果可能,再次将无效字符转换为?).带有2nd参数的String构造函数从字节数组创建一个新的String,其中字节采用指定的编码.现在,因为你刚刚source.getBytes(inputEncoding)获得这些字节,所以它们没有被编码outputEncoding(除非编码使用相同的值,这对于"普通"字符是常见的abcd,但不同于更复杂的重音字符éêäöñ).

那么这是什么意思?这意味着当你拥有Java时String,一切都很棒.Strings是unicode,意味着你的所有角色都是安全的.当您需要将其转换String为字节时,问题就出现了,这意味着您需要决定编码.选择Unicode兼容的编码,如UTF8,UTF16等是很大的.这意味着即使你的String包含各种奇怪的字符,你的角色仍然是安全的.如果选择不同的编码(US-ASCII支持最少),则String必须仅包含编码支持的字符,否则将导致字节损坏.

现在终于有一些好的和坏的用法的例子.

String myString = "Feng shui in chinese is ??";
byte[] bytes1 = myString.getBytes("UTF-8");  // Bytes correct
byte[] bytes2 = myString.getBytes("US-ASCII"); // Last 2 characters are now corrupted (converted to question marks)

String nordic = "Här är några merkkejä";
byte[] bytes3 = nordic.getBytes("UTF-8");  // Bytes correct, "weird" chars take 2 bytes each
byte[] bytes4 = nordic.getBytes("ISO-8859-1"); // Bytes correct, "weird" chars take 1 byte each
String broken = new String(nordic.getBytes("UTF-8"), "ISO-8859-1"); // Contains now "Här är några merkkejä"
Run Code Online (Sandbox Code Playgroud)

最后一个例子表明,尽管两种编码都支持北欧字符,但它们使用不同的字节来表示它们.因此,没有将String从一个编码转换为另一个编码的事情,你永远不应该使用破坏的例子.

另请注意,您应始终指定使用的编码(使用getBytes()new String()),因为您不能相信默认编码始终是您想要的编码.

作为最后一个问题,Charset和Encoding不是一回事,但它们非常相关.

¹从技术上讲,String内部存储在JVM中的方式是UTF-16编码,但它对Java代码没有影响.