如何将文本从utf8 / cp1251(windows cyrillic)转换为DOS Cyrillic(cp866)
我找到了这个例子:
Charset fromCharset = Charset.forName("utf8");
Charset toCharset = Charset.forName("cp866");
String text1 = "Николай"; // my name in bulgarian
String text2 = "Nikolay"; // my name in english
System.out.println("TEXT1 :[" + toCharset.decode(fromCharset.encode(text1)).toString() + "]");
System.out.println("TEXT2 :[" + toCharset.decode(fromCharset.encode(text2)).toString() + "]");
输入是:
TEXT1 :[╨Э╨╕╨║╨╛╨╗╨░╨╣] // WRONG
TEXT2 :[Nikolay] // CORRECT
问题出在哪里?
答案 0 :(得分:13)
第一个:如果你有一个String
对象,那么它就不再有编码了,它是一个纯Unicode字符串(*)!
在Java中,当您从字节(byte[]
)转换为字符串(String
)时,编码仅用于 ,反之亦然。 (理论上你可以从byte[]
直接转换为byte[]
,但我还没有看到用Java完成转换。
如果你有一些cp1251编码数据,那么它必须是byte[]
(即一个字节数组)或某种流(例如,作为{提供给你) {1}})。
如果你想提供一些数据为cp866,那么你必须提供它作为InputStream
或某种流(例如`OutputStream)。
另外:没有“utf8 / cp1251”这样的东西。 UTF-8和CP-1251是几乎不相关的字符编码。您的输入是UTF-8或CP-1251(或其他)。它不可能都是(+)。
(*)是的,严格来说它有一个编码,它是UTF-16,但是对于大多数用途,你可以(而且应该)把它想象成“无编码的理想Unicode字符串”
(+)严格来说,如果它只使用在两种编码中编码为相同字节的字符,通常是ASCII子集
答案 1 :(得分:5)
问题是你正在尝试解码一个编码的输出,就好像它是一个不同的编码。
想象一下,你有一个只能写出JPEG的程序,另一个只能读取PNG的程序......你希望能用第二个程序读取第一个程序的输出吗?
在这种情况下,两种编码碰巧兼容ASCII字符,但从根本上说你做错了。
如果您的文本已经是UTF-8,您应该使用UTF-8编码从二进制数据读取到Unicode字符串,然后使用其他编码将其写出二进制数据。 Unicode是基本的中间步骤,作为Java的本机文本格式。这相当于将JPEG输出加载到另一个程序中,该程序可以在您使用第二个应用程序读取之前执行转换为PNG。
答案 2 :(得分:4)
简短解决您的问题:
System.out.write("ВАСЯ\n".getBytes("cp866")); // its right
System.out.println("ВАСЯ".getBytes("cp866")); // its wrong
cmd.exe的结果:
C:\ Documents and Settings \ afram \Моидокументы\ NetBeansProjects \ Encoding \ dist> java -jar Encoding.jar
ВАСЯ
[B @ 1bab50a
答案 3 :(得分:3)
<强>短强>
将utf8 String解码为cp866。由于utf8和cp866只共享ascii符号,所以其他一切都会被破坏。
<强>长:强>
Java在内部使用UTF-16表示字符串,所有String对象都以UTF-16编码。
Charset.encode()
创建一个包含选择编码中的String的bytebuffer,在您的代码中,它将Java UTF-16字符串转换为utf-8编码的字节数组。
Charset.decode()
将一个bytebuffer编码为Charset,并将其转换为Java UTF-16字符串。在您的情况下,您使用utf-8
解码器解码cp866
字符串,从而导致错误的字符串。
由于java Strings具有指定的编码,因此在读取或写入时必须指定它。 InputStreamReader和OutputStreamWriter都为ctors提供了Charset参数。
这里有一个关于如何转换文件/流的示例。
//input the source is encoded in fromCharset
BufferedReader in = new BufferedReader(new InputStreamReader(...,fromCharset));
//output the target will be encoded in toCharset
PrintWriter out = new PrintWriter(new OutputStreamWriter(...,toCharset));
//reads a decoded String
String line = in.readLine();
while(line != null)
{
out.println(line);
line = in.readLine();
}
答案 4 :(得分:0)
问题是,你的控制台输出不是cp866。控制台是一个,转换是其他。
java中的内部字符串始终是unicode,charset对于输入/输出操作很重要。您尚未指定要对“转换”字符串执行的操作,但您应该明确地看到类InputStreamReader / OutputStreamWriter。它们为您的I / O操作提供字符集设置。