如何在Java中将八进制字符序列转换为Unicode

3

嗨,有以下字符串:

让我们首先从最明显的问题开始。这就是"展开(unfurl)"是什么意思。

它应该显示为 前三个数字(\342\200\231)实际上代表一个八进制序列http://graphemica.com/%E2%80%99,它的Unicode等效项是\u2019

类似地,\342\200\234表示一个八进制序列http://graphemica.com/%E2%80%9C,它的Unicode等效项是\u201C

是否有任何库或函数可以将这些八进制序列转换为它们的Unicode等效项?


你的字符串是否包含直接写出的八进制序列,例如实际字符“反斜杠”,数字“三”,数字“四”,数字“二”,“反斜杠”,数字“二”,数字“零”等? - Kevin Anderson
是的..看一下问题中的示例字符串,就是那样的。 - Vivek Kothari
1
字符串的来源是什么?它是从文本文件中读取的,还是像Java源文件中的字符串文字那样编写的?这将对答案产生很大的影响。 - DodgyCodeException
1
注意:说“unicode equivalent”不太对。那是Java源文件中的UTF-16转义。但UTF-8和UTF-16是Unicode字符集的编码。你的八进制字节使用了UTF-8编码。 - Tom Blodget
2个回答

5

您展示的字节是UTF-8编码的表示形式,这只是Unicode的众多形式之一。Java被设计为处理这样的编码作为字节序列(如数组和流),而不是字符和字符串。更加清晰的方法是实际使用字节,但是您必须处理Java字节是带符号的(-128..+127),而所有多字节UTF-8代码(按设计)都在8位空间的上半部分:

byte[] a = {'L','e','t',(byte)0342,(byte)0200,(byte)0231,'s'};
System.out.println (new String (a,StandardCharsets.UTF_8));
// or arguably uglier
byte[] b = {'L','e','t',0342-256,0200-256,0231-256,'s'};
System.out.println (new String (b,StandardCharsets.UTF_8));

但如果你想要更接近原始的内容,你可以稍微作弊一下,把一个包含UTF-8字节的字符串(无符号字符)当做包含Unicode范围0000-00FF的8位字符来处理,这个范围被定义为与ISO-8859-1相同:

byte[] c = "Let\342\200\231s".getBytes(StandardCharsets.ISO_8859_1);
System.out.println (new String (c,StandardCharsets.UTF_8));

"Let's" 是循环的,但很可能是问题所需的。源文件编码 → 八进制字符串转义为 UTF-16 代码单元 → 重新解释为 ISO 8895-1 字节 → 转换回 UTF-16 作为 UTF-8 字节。干得好。生产代码需要大量的代码注释。 - Tom Blodget
@TomBlodget先生,您看到Vivek在我的回答下面的评论了吗?实际上输入是没有转义字符的。 - Soner from The Ottoman Empire
@snr \342 是 Java 字符串中的转义字符,表示 \u00E2。你的回答对 \ 进行了转义,以生成反斜杠字符。 - Tom Blodget
1
但是这样的代码有什么用呢?如果字符串文字在Java源文件中,为什么不直接更改源文件以使用\uNNNN - DodgyCodeException
明白了,谢谢。我确实说过“两个字节组合成一个UTF-8输出字符”,但实际上是三个字节,而不是两个,我漏掉了那部分。 - Abhijit Sarkar
显示剩余4条评论

-1
在Java中,只能使用十六进制而不能使用八进制实现此功能。
这段代码可正常工作:
System.out.println("\u2019");

Java支持八进制转义序列可能仅仅是出于历史原因。这些转义序列起源于C语言(或者也许是C的前身B和BCPL),在那个PDP-7等计算机统治地球、大量编程使用汇编语言或直接使用机器码的年代,八进制是写指令代码的首选数字基数,而且当时还没有Unicode,只有ASCII,所以三个八进制数字就足以表示整个字符集。

到了Unicode和Java的时代,八进制已经基本上被十六进制取代,成为当十进制不够用时的首选数字基数。因此,Java有它的\u转义序列,可以使用十六进制数字。八进制转义序列可能仅仅是为了让C程序员感到舒适,并且方便从C程序中复制粘贴字符串常量到Java程序中。


decode函数无法将其转换为Unicode。Integer.decode("\342\200\234")会抛出异常。 - Vivek Kothari
请告诉我它是否产生了您所期望的结果。 - Guilherme Mussi
不对,它输出的是<â>,应该输出<’>。 - Vivek Kothari
好的,我已经调查过了,用八进制在Java中实现这个是不可能的。只有用十六进制才能实现。 - Guilherme Mussi
如果不用Java,我们能用Javascript做吗? - Vivek Kothari
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接