Java Unicode编码

Mar*_*eon 36 java unicode character-encoding

Java char2个字节(最大大小为65,536)但是有95,221个 Unicode字符.这是否意味着您无法在Java应用程序中处理某些Unicode字符?

这可归结为您使用的字符编码吗?

ken*_*ytm 35

如果你足够小心,你可以处理它们.

Java char是一个UTF-16代码单元.对于代码点> 0xFFFF的字符,它将被编码为2 char秒(代理对).

有关如何在Java中处理这些字符,请参阅http://www.oracle.com/us/technologies/java/supplementary-142654.html.

(顺便说一句,在Unicode 5.2中,1,114,112个插槽中有107,154个指定的字符.)


Mic*_*rdt 14

Java使用UTF-16.单个Java char只能表示基本多语言平面中的字符.其他角色必须由两个代理对表示char.这反映在API方法中,例如String.codePointAt().

是的,这意味着当与基本多语言平面之外的字符一起使用时,许多Java代码会以某种方式破坏.

  • @Bart:length()将这样的字符计为两个字符,substring()也会这样做,并且很乐意将它们分解,导致UTF-16无效.这是因为只有在Java被设计并且Java没有进行破坏性更改之后,这些字符才会成为Unicode的一部分.因此,增加了新方法来处理代理对,但旧方法保持不变. (6认同)
  • `String.length`,`substring`等如何处理这些字符的字符串? (2认同)
  • +1表示大多数Java代码都被破坏了. (2认同)

leo*_*loy 13

要添加其他答案,需要记住一些要点:

  • 一个Java的char需要总是16位.

  • 一个Unicode字符,当为UTF-16编码,以"几乎总是"(不总是)16位:这是因为有超过64K Unicode字符.因此,Java char不是Unicode字符(虽然"几乎总是").

  • "几乎总是",在上面,表示Unicode的64K第一个代码点,范围0x0000到0xFFFF(BMP),在UTF-16编码中占16位.

  • 非BMP("罕见")Unicode字符表示为两个Java字符(代理表示).这也适用于作为字符串的文字表示:例如,字符U + 20000被写为"\ uD840\uDC00".

  • Corolary:string.length()返回java字符的数量,而不是Unicode字符的数量.只返回一个"罕见"unicode字符(例如U + 20000)的字符串length() = 2.相同的考虑适用于处理char序列的任何方法.

  • Java几乎没有处理非BMP unicode字符的智能.有一些实用方法将字符视为代码点,表示为int,例如:Character.isLetter(int ch).这些是真正的全Unicode方法.


Bas*_*que 5

你说:

Java char 是 2 个字节(最大大小为 65,536),但有 95,221 个 Unicode 字符。

Unicode 增长

实际上,Unicode 中定义的字符库存急剧增加。Unicode 继续增长——不仅仅是因为表情符号

  • Unicode 13 中的 143,859 个字符(Java 15,发行说明
  • Unicode 12.1 (Java 13 & 14) 中的 137,994 个字符
  • Unicode 10(Java 11 和 12)中的 136,755 个字符
  • Unicode 8 (Java 9) 中的 120,737 个字符
  • Unicode 6.2 (Java 8) 中的 110,182 个字符
  • Unicode 6.0 (Java 7) 中的 109,449 个字符
  • Unicode 4.0(Java 5 和 6)中的 96,447 个字符
  • Unicode 3.0 (Java 1.4) 中的 49,259 个字符
  • Unicode 2.1 (Java 1.1.7) 中的 38,952 个字符
  • Unicode 2.0 (Java 1.1) 中的 38,950 个字符
  • Unicode 1.1.5 (Java 1.0) 中的 34,233 个字符

char 是遗产

char类型早已过时,现在是legacy

使用代码点编号

相反,您应该使用代码点编号。


你问:

这是否意味着您无法在 Java 应用程序中处理某些 Unicode 字符?

char类型可以处理不到今天的 Unicode 字符的一半。

要表示任何 Unicode 字符,请使用代码点编号。永远不要使用char.

Unicode 中的每个字符都分配有一个代码点编号。这些范围超过一百万,从 0 到 1,114,112。在与上面列出的数字进行比较时进行数学计算,这意味着该范围内的大多数数字尚未分配给一个字符。其中一些号码被保留为私人使用区,永远不会被分配。

String班已获得方法与码点号的工作,为做Character课。

通过从零开始的索引号获取字符串中任何字符的代码点号。在这里,我们得到97了这封信a

int codePoint = "Cat".codePointAt( 1 ) ; // 97 = 'a', hex U+0061, LATIN SMALL LETTER A.
Run Code Online (Sandbox Code Playgroud)

对于更通用CharSequence而不是String,请使用Character.codePointAt.

我们可以获得代码点编号的 Unicode 名称。

String name = Character.getName( 97 ) ; // letter `a`
Run Code Online (Sandbox Code Playgroud)

拉丁文小写字母 A

我们可以得到一个字符串中所有字符的代码点编号的流。

IntStream codePointsStream = "Cat".codePoints() ;
Run Code Online (Sandbox Code Playgroud)

我们可以把它转换成一个ListInteger对象。请参阅如何将 Java 8 IntStream 转换为列表?.

List< Integer > codePointsList = codePointsStream.boxed().collect( Collectors.toList() ) ;
Run Code Online (Sandbox Code Playgroud)

可以String通过调用将任何代码点编号更改为单个字符的 a Character.toString

String s = Character.toString( 97 ) ; // 97 is `a`, LATIN SMALL LETTER A. 
Run Code Online (Sandbox Code Playgroud)

一种

我们可以String从一个IntStream代码点编号生成一个对象。请参阅从代码点编号的 IntStream 创建字符串?.

IntStream intStream = IntStream.of( 67 , 97 , 116 , 32 , 128_008 ); // 32 = SPACE, 128,008 = CAT (emoji).

String output =
        intStream
                .collect(                                     // Collect the results of processing each code point.
                        StringBuilder :: new ,                // Supplier<R> supplier
                        StringBuilder :: appendCodePoint ,    // ObjIntConsumer<R> accumulator
                        StringBuilder :: append               // BiConsumer<R,?R> combiner
                )                                             // Returns a `CharSequence` object.
                .toString();                                  // If you would rather have a `String` than `CharSequence`, call `toString`. 
Run Code Online (Sandbox Code Playgroud)


你问:

这是否归结为您使用的字符编码?

在内部,StringJava 中的 a 始终使用UTF-16

在从 Java 字符串导入或导出文本时,您只能使用其他字符编码。

所以,回答你的问题,不,字符编码在这里没有直接关系。将文本放入 Java 后String,它采用 UTF-16 编码,因此可以包含任何 Unicode 字符。当然,要查看该字符,您必须使用带有为该特定字符定义的字形的字体。

从 Java 字符串导出文本时,如果指定的旧字符编码无法表示文本中使用的某些 Unicode 字符,则会出现问题。所以使用现代字符编码,现在意味着UTF-8因为UTF-16 现在被认为是有害的