[英]Converting String from One Charset to Another
我正在将字符串从一个字符集转换为另一个字符集,并阅读了许多示例,最后找到了下面的代码,这对我来说看起来不错,而且作为字符集编码的新手,我想知道,这是否是正确的方法它 。
public static byte[] transcodeField(byte[] source, Charset from, Charset to) {
return new String(source, from).getBytes(to);
}
要将 String 从ASCII转换为 EBCDIC ,我必须执行以下操作:
System.out.println(new String(transcodeField(ebytes,
Charset.forName("US-ASCII"), Charset.forName("Cp1047"))));
并且要从EBCDIC转换为 ASCII ,我必须这样做:
System.out.println(new String(transcodeField(ebytes,
Charset.forName("Cp1047"), Charset.forName("US-ASCII"))));
您找到的代码 ( transcodeField
) 不会将String
从一种编码转换为另一种编码,因为String
没有编码¹。 它将字节从一种编码转换为另一种编码。 该方法仅在您的用例满足 2 个条件时才有用:
在这种情况下,它是直截了当的:
byte[] out = transcodeField(inbytes, Charset.forName(inEnc), Charset.forName(outEnc));
如果输入数据包含无法在输出编码中表示的字符(例如将复杂的UTF8
为ASCII
),这些字符将被替换为?
替换符号,数据将被破坏。
然而, 很多人问“ 如何将字符串从一种编码转换为另一种编码”, 很多人用以下代码段回答:
String s = new String(source.getBytes(inputEncoding), outputEncoding);
这是完整的公牛****。 getBytes(String encoding)
方法返回一个字节数组,其中包含以指定编码编码的字符(如果可能,再次将无效字符转换为?
)。 带有第二个参数的 String 构造函数从字节数组中创建一个新的 String,其中字节采用指定的编码。 现在,由于您刚刚使用source.getBytes(inputEncoding)
来获取这些字节,因此它们不会在outputEncoding
编码(除非编码使用相同的值,这对于像abcd
这样的“普通”字符很常见,但与更复杂的字符不同,例如重音字符éêäöñ
)。
那么这是什么意思? 这意味着当您拥有 Java String
,一切都很棒。 Strings
是 unicode,这意味着您的所有字符都是安全的。 当您需要将该String
转换为字节时,问题就出现了,这意味着您需要决定一种编码。 选择一个 unicode 兼容的编码,比如UTF8
、 UTF16
等,是很棒的。 这意味着即使您的 String 包含各种奇怪的字符,您的字符仍然是安全的。 如果您选择不同的编码( US-ASCII
支持最少),您的字符串必须仅包含编码支持的字符,否则会导致字节损坏。
现在终于有一些好的和坏的用法的例子。
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ä"
最后一个例子表明,尽管两种编码都支持北欧字符,但它们使用不同的字节来表示它们,并且在Mojibake解码结果时使用了错误的编码。 因此,没有“将字符串从一种编码转换为另一种编码”这样的事情,您永远不应该使用损坏的示例。
另请注意,您应该始终指定使用的编码(同时使用getBytes()
和new String()
),因为您不能相信默认编码总是您想要的。
最后一个问题, 字符集和编码不是一回事,但它们非常相关。
¹ 从技术上讲,字符串在 JVM 中的内部存储方式是 UTF-16 编码,直到 Java 8,以及从 Java 9 开始的变量编码,但开发人员不需要关心这一点。
笔记
有可能有一个损坏的字符串,并且能够通过摆弄编码来使它不损坏,这可能是这种“将字符串转换为其他编码”误解的来源。
// Input comes from network/file/other place and we have misconfigured the encoding
String input = "Här är några merkkejä"; // UTF-8 bytes, interpreted wrongly as ISO-8859-1 compatible
byte[] bytes = input.getBytes("ISO-8859-1"); // Get each char as single byte
String asUtf8 = new String(bytes, "UTF-8"); // Recreate String as UTF-8
如果input
没有字符损坏,则字符串现在将是“固定的”。 然而,正确的方法是在读取input
时使用正确的编码,而不是之后修复它。 特别是如果它有可能被损坏。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.