2009-08-13 85 views
5

我想解码Java中的一些UTF-8字符串。 这些字符串包含一些组合unicode字符,如CC 88(组合diaresis)。 字符序列似乎没问题,根据http://www.fileformat.info/info/unicode/char/0308/index.htmJava UTF-8奇怪的行为

但是转换成String之后的输出无效。 有什么想法?

byte[] utf8 = { 105, -52, -120 }; 
System.out.print("{{"); 
for(int i = 0; i < utf8.length; ++i) 
{ 
    int value = utf8[i] & 0xFF; 
    System.out.print(Integer.toHexString(value)); 
} 
System.out.println("}}"); 
System.out.println(">" + new String(utf8, "UTF-8")); 

输出:

 
    {{69cc88}} 
    >i? 

回答

9

其中您输出到(例如窗户)操纵台可能不支持Unicode,并且可以裂伤的字符。控制台输出不是数据的良好表示。

尝试将输出写入文件,而不是确保FileWriter上的编码正确,然后在一个适用于Unicode的编辑器中打开该文件。

或者,使用调试器来确保字符是你所期望的。只是不要相信控制台。

+0

+1:在终端(gnome-terminal)的Ubuntu 9.04上,输出是带有diaresis的i,你可能期望它。 – 2009-08-13 13:48:10

+0

我很喜欢这个词“diaeresis”。我可能不得不在谈话中更频繁地使用它。 – skaffman 2009-08-13 13:49:56

+1

:) 尝试“变音符号”,你将成为晚上的男人。 – 2009-08-13 13:55:56

4

代码很好,但是skaffman说你的控制台可能不支持合适的字符。

为了测试是肯定的,你需要打印出的字符的Unicode值:

public class Test { 
    public static void main(String[] args) throws Exception { 
     byte[] utf8 = { 105, -52, -120 }; 
     String text = new String(utf8, "UTF-8"); 
     for (int i=0; i < text.length(); i++) { 
      System.out.println(Integer.toHexString(text.charAt(i))); 
     } 
    } 
} 

这将打印69,308 - 这是correct(U + 0069,U + 0308)。

4

你是对的。谢谢 !!

这里怎么我终于解决了这个问题,在Eclipse上的Windows:

  • 在运行配置,参数标签,我补充说:“-Dfile.encoding=UTF-8”的VM参数
  • 在运行配置中,普通标签我设置控制台编码为UTF-8

我修改了代码如下:

byte[] utf8 = { 105, -52, -120 }; 
System.out.print("{{"); 
for(int i = 0; i < utf8.length; ++i) 
{ 
    int value = utf8[i] & 0xFF; 
    System.out.print(Integer.toHexString(value)); 
} 
System.out.println("}}"); 

PrintStream sysout = new PrintStream(System.out, true, "UTF-8"); 
sysout.print(">" + new String(utf8, "UTF-8")); 

输出:

 
{{69cc88}} 
> ï 

谢谢!

+0

如果要使用PrintStream自己编码数据,则不需要“-Dfile.encoding = UTF-8”开关。 (对于需要了解系统编码的任何代码,手动设置“file.encoding”属性可能会有问题。) – McDowell 2009-08-13 14:41:39

1

在将它们写入stdout之前,Java并非不合理地将Unicode字符编码为本地系统编码字节。一些操作系统,如许多Linux发行版,使用UTF-8作为它们的默认字符集,这很好。

由于各种向后兼容性原因,Windows在Windows上有点不同。默认系统编码将是“ANSI”代码页之一,如果您打开默认命令提示符(cmd.exe),它将是旧的“OEM”DOS代码页之一(虽然可以在那里获得ANSI和Unicode with a bit of work )。由于U + 0308不在任何“ANSI”字符集中(在你的情况下可能为1252),它将被编码为错误字符(通常是问号)。

为Unicode启用一切的替代方法是normalize合成序列U + 0069 U + 0308到单个字符U + 00EF:

public static void emit(String foo) throws IOException { 
    System.out.println("Literal: " + foo); 
    System.out.print("Hex: "); 
    for (char ch : foo.toCharArray()) { 
     System.out.print(Integer.toHexString(ch & 0xFFFF) + " "); 
    } 
    System.out.println(); 
    } 

    public static void main(String[] args) throws IOException { 
    String foo = "\u0069\u0308"; 
    emit(foo); 
    foo = Normalizer.normalize(foo, Normalizer.Form.NFC); 
    emit(foo); 
    } 

windows-1252,这个代码将发出:

 
Literal: i? 
Hex: 69 308 
Literal: ï 
Hex: ef