1

我正在尝试将包含 CJK ExtB 计划中的 Unicode 字符的 Java 字符串转换为十进制 NCR。

例如(您可以尝试使用http://people.w3.org/rishida/tools/conversion/):

  • “游钖堃”应转换为游鍚堃
  • “怀”应该转换为𧦧懷

这是我尝试过的(在 Scala 中):

def charToHex(char: Char) = "&#%d;" format(char.toInt)
def stringToHex (string: String) = string.flatMap(charToHex)

println (stringToHex("游鍚堃")) // 游鍚堃
println (stringToHex("懷"))   // ��懷
println ("懷".toCharArray().length) // Why it is 3?

如您所见,它在第一种情况下正确转换,将三个 unicode 字符转换为三个 NCR。

但是在第二种情况“怀”中,只有两个unicode字符,但是Java/Scala似乎认为它是一个包含三个字符的字符串。

那么,这里发生了什么,我怎样才能像我提到的网站上的转换器一样正确转换第二种情况?非常感谢。

更新:

  • 我的源代码文件使用的是 UTF-8。
  • 这是 "怀".toCharArray() 的结果
    • char[] = ?, char.toInt = 55390
    • char[] = ?, char.toInt = 56743
    • char[] = 懷, char.toInt = 25079

现在我想我知道发生了什么。字符“”在 UTF-16 中编码为 0xD85E 0xDDA7,是 4 个字节而不是 2 个字节。所以转换为char数组时需要2个元素,其中数据类型char只能表示2个字节。

4

3 回答 3

7

Java(以及因此 Scala)对其字符串使用 UTF-16 编码,这意味着 2^16-1 以上的所有 unicode 代码点必须用两个字符表示。(实际上,编码方案比那个复杂一点。)无论如何,length是一种在较低级别操作的方法--characters--因此它返回字符数。

如果您想找出代码点的数量,这可能是您在说“两个 unicode 字符”(例如打印出来的两个符号)时直观地想到的,您需要使用s.codePointCount(0,s.length). 如果要将它们转换为十六进制,则需要使用码点而不是Chars,因为并非所有码点都适合。我对这个问题的回答包含将字符串转换为代码点的 Scala 代码。(效率不高;如果您正在对大字符串进行繁重的文本处理,您可能希望将其重写为使用数组/ArrayBuffer。)

于 2011-03-07T10:39:41.650 回答
2

这就是他们所说的 unicode 语言中的“代理”。例如,

"懷" foreach { c =>
  println(java.lang.Character.UnicodeBlock.of(c))
}

印刷

HIGH_SURROGATES
LOW_SURROGATES
CJK_UNIFIED_IDEOGRAPHS

顺便说一句,我也在台湾。如果你对 Scala 感兴趣,我们应该聚在一起谈谈。如果您有兴趣,我的电子邮件在我的个人资料中。

于 2011-03-07T13:12:37.943 回答
0

检查文件编码。您的 IDE 或构建脚本必须知道该文件是 UTF-8 还是 UTF-16(您使用哪一个?)。如果您定义BOM,请检查它是否合适。

于 2011-03-07T09:48:41.133 回答