如何在给定字符集的情况下将单个字符代码转换为`char`?

时间:2017-02-03 17:28:47

标签: java ascii

我想将十进制转换为ascii,这是代码返回意外结果。这是我正在使用的代码。

public static void main(String[] args) {
    char ret= (char)146;  
    System.out.println(ret);// returns nothing. 

我希望能够获得单曲"'"根据{{​​3}} 有谁遇到过这个?感谢。

2 个答案:

答案 0 :(得分:6)

所以,有几件事。

首先,您链接到的页面会说明有关代码点范围:

  

扩展的ASCII码(字符代码128-255)

     

8位ASCII表有几种不同的变体。下表符合ISO 8859-1,也称为ISO Latin-1。代码128-159包含Microsoft®WindowsLatin-1扩展字符。

这是错误的,或者至少对我来说是误导性的措辞。 ISO 8859-1 / Latin-1 does not define code point 146(和another reference just because。所以这已经在惹麻烦了。如果您通过String进行转换,也可以看到此信息:

String s = new String(new byte[] {(byte)146}, "iso-8859-1");
System.out.println(s);

输出相同的“意外”结果。它出现它们实际指的是Windows-1252集(又名“Windows Latin-1”,但这个名称现在几乎完全过时了),它定义了代码点作为正确的单引号(对于在146处提供此字符的其他字符集,请参阅this list并查找在0x92处提供该字符的编码),我们可以对此进行验证:

String s = new String(new byte[] {(byte)146}, "windows-1252");
System.out.println(s);

所以第一个错误是页面令人困惑。

但是最大的错误是你不能按照自己的方式去做你想做的事情。 Java中的char是一个UTF-16代码点(或者一半,如果你代表补充字符> 0xFFFF,单个char对应一个BMP点,一对或者int对应于整个范围,包括补充范围。)

不幸的是,Java并没有为单字符转换公开大量的API。即使Character也没有任何现成的方法可以将您选择的字符集转换为UTF-16。

因此,一个选项是通过String进行,如上面的示例所示,例如:将您的代码点表示为原始byte[]数组并从那里转换:

String s = new String(new byte[] {(byte)146}, "windows-1252");
System.out.println(s);
char c = s.charAt(0);
System.out.println(c);

您可以通过char再次抓取s.charAt(0)。请注意,执行此操作时必须注意字符集。在这里我们知道我们的字节序列对指定的编码有效,并且我们知道结果只有一个char长,所以我们可以这样做。

但是,你必须注意一般情况下的事情。例如,您的字节序列和字符集可能会产生UTF-16补充字符范围内的结果。在这种情况下,s.charAt(0)是不够的,而s.codePointAt(0)中需要存储int

作为替代方案,同样的警告,您可以使用Charset进行解码,尽管它很笨重,例如:

Charset cs = Charset.forName("windows-1252");
CharBuffer cb = cs.decode(ByteBuffer.wrap(new byte[] {(byte)146}));
char c = cb.get(0);
System.out.println(c);

请注意,我并不完全确定Charset#decode如何处理补充字符并且现在无法真正测试(但任何人都可以随意加入)。

顺便说一下:在你的情况下,146(0x92)直接转换为char对应于UTF-16字符“PRIVATE USE TWO”(see also),并且所有的赌注都是关闭的你最终会在那里展示。此字符为classified by Unicode as a control character,似乎属于为ANSI终端控制保留的字符范围(尽管实际上并未使用AFAIK,但无论如何都在该范围内)。如果某些语言环境中的浏览器可能将其作为兼容性的右单引号,我也不会感到惊讶,但是终端对它做了一些奇怪的事情。

另外,fyi是right single quote is 0x2019的官方UTF-16代码点。您可以使用该值可靠地将其存储在char中,例如:

System.out.println((char)0x2019);

您还可以通过查看从Windows-1252转换后的值来自行查看:

String s = new String(new byte[] {(byte)146}, "windows-1252");
char c = s.charAt(0);
System.out.printf("0x%x\n", (int)c); // outputs 0x2019

或者,为了完整性:

String s = new String(new byte[] {(byte)146}, "windows-1252");
int cp = s.codePointAt(0);
System.out.printf("0x%x\n", cp); // outputs 0x2019

答案 1 :(得分:0)

您提到的页面提到值160到255对应于ISO-8859-1(又名拉丁语1)表;对于128到159范围内的值,它们来自拉丁语1的Windows特定变体(ISO-8859-1保留未定义的范围,由操作系统分配)。

Java字符基于UTF16,它本身基于Unicode表。如果您想特别引用正确的引号字符,可以在Java中将其指定为'\u2019'(参见http://www.fileformat.info/info/unicode/char/2019/index.htm)。