UTF-16 分成 2 个字符

UTF-16 split in 2 chars

我一直认为 java 使用 UTF-16 对其字符进行内部编码。它使用 u+xxxx 格式来表示字符代码以及它使用 16 位来存储 char.

的事实证实了这一点。

但有时UTF-16需要2个字节以上那样的话java需要2char来表示1UTF-16 字符.

旁注:这让我想知道说 "java just supports the Unicode character set, and uses 16-bit cells to store characters".

是否更正确

问题:第一个 char 是否提供了一些方法来确定第二个 char 被使用,或者两者属于一起?

是的,UTF-16 是在 Unicode 将 Unicode 1.0 的 65536 个代码点限制扩展到今天的 1114112 个代码点限制时发明的。

这允许它支持整个通用字符集,同时保持与 UCS-2 的兼容性;将所有 Unicode 字符作为双字节单元的过时编码,正是因为它无法在 Unicode 2.0 或更高版本中对所有 Unicode 字符进行编码。

Does the first char offer some method to determine that a second char is used, or that the 2 belong together?

是的,在 UTF-16 中,两个字节的单位是:

  1. 高代理项,必须始终跟有低代理项。在 0xD8000xDBFF 之间,isHighSurrogate 将 return true.
  2. 必须始终跟随高代理项的低代理项。在 0xDC000xDFFF 之间,isLowSurrogate 将 return true.
  3. 非代理人。

非代理映射直接与一个相同码位的BMP字符。

代理人组合起来代表星界角色:

  1. 从代码点中减去 0x010000。
  2. 将前 10 位添加到 0xD800 以获得高代理项。
  3. 将低 10 位添加到 0xDC00 以获得低代理项。

在 Java 中,您可以通过首先使用代码点检查 int 上的 isBmpCodePoint 来执行此操作。如果这是真的,那么您可以将其转换为 char 以获得对其进行编码的单个 UTF-16 单元。否则,您可以调用 highSurrogate 获取第一个 char 并调用 lowSurrogate 获取第二个。

isBmpCodePoint 一样,您可以使用 charCount,其中 returns 1 用于 BMP 字符,2 如果您需要代理。如果您要创建 12 个字符的数组来保存值,这将很有用。

由于永远不会为代理代码点分配字符,这意味着编码对于整个通用字符集都是明确的。

它也是自我纠正的,可以隔离流中的错误,而不是导致所有其他字符被误读。例如。如果我们找到一个孤立的低代理项,我们知道该位是错误的,但仍然可以读取流的其余部分。

一些完整的示例,但我在 Java 中不太热(另一方面,我很了解 Unicode,这就是我用来回答这个问题的知识),所以如果有人发现 n00b Java 错误,但认为我的 Unicode 知识部分正确,请继续并相应地编辑此 post:

"" 是一个带有单个 Unicode 字符的字符串,U+10300 是旧斜体字母表中的一个字母。在大多数情况下,这些半开玩笑地称为 "Astral Planes" 的字符相对晦涩,因为 Unicode 联盟试图在不超出更易于使用的 BMP(基本多语言平面;基本多语言平面; U+0000U+FFFF,尽管有时列为“U+0000U+FFFD,因为 U+FFFEU+FFFF 都是非字符,不应该大多数情况下使用)。

(如果你正在试验这个,那么直接使用 </code> 的那些将取决于你的文本编辑器处理它的能力)。</p> <p>如果你检查 <code>"".length 你会得到 2 因为 length 给你的是 UTF-16 编码单元的数量,而不是字符的数量。

new StringBuilder().appendCodePoint(0x10300).toString() == "" 应该 return true.

Character.charCount(0x10300) 将 return 2 因为我们需要两个 UTF-16 char 来编码它。 Character.isBmpCodePoint(0x10300) 将 return false.

Character.codePointAt("", 0) 将 return 663040x10300,因为当它看到高代理时,它包括在计算中读取以下低代理。

Character.highSurrogate(0x10300) == 0xD800 && Character.lowSurrogate(0x10300) == 0xDF00 是正确的,因为这些是应该将字符拆分成以 UTF-16 编码的高位和低位代理项。

同样 "".charAt(0) == 0xD800 && "".charAt(1) == 0xDF00 因为 charAt 处理 UTF-16 单位,而不是 Unicode 字符。

出于同样的原因 "" == "\uD800\uDF00" 对两个代理项使用转义符。