簡體   English   中英

Java Unicode 編碼

[英]Java Unicode encoding

Java char2 個字節(最大大小為 65,536),但有95,221 個Unicode 字符。 這是否意味着您無法在 Java 應用程序中處理某些 Unicode 字符?

這是否歸結為您使用的字符編碼?

如果你足夠小心,你可以處理所有這些。

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 個分配的字符。)

Java 使用UTF-16 單個 Java char只能表示來自基本多語言平面的字符。 其他字符必須由兩個char代理對表示。 這反映在 API 方法中,例如String.codePointAt()

是的,這意味着許多 Java 代碼在與基本多語言平面之外的字符一起使用時會以一種或另一種方式中斷。

要添加到其他答案中,請記住以下幾點:

  • Java char總是16 位

  • Unicode character ,當編碼為 UTF-16 時,“幾乎總是”(不總是)16 位:這是因為有超過 64K 的 unicode 字符。 因此,Java 字符不是 Unicode 字符(盡管“幾乎總是”是)。

  • 上面的“幾乎總是”表示 Unicode 的第一個 64K 代碼點,范圍從 0x0000 到 0xFFFF ( BMP ),在 UTF-16 編碼中占 16 位。

  • 非 BMP(“稀有”)Unicode 字符表示為兩個 Java 字符(代理表示)。 這也適用於作為字符串的文字表示: 例如,字符 U+20000 寫為“\?\?”。

  • 推論: string.length()返回 java 字符的數量,而不是 Unicode 字符的數量。 只有一個“稀有”unicode 字符(例如 U+20000)的字符串將返回length() = 2 同樣的考慮適用於任何處理字符序列的方法。

  • Java 在處理整個非 BMP unicode 字符方面幾乎沒有什么智能。 有一些實用方法將字符視為代碼點,表示為整數,例如: Character.isLetter(int ch) 這些才是真正的全 Unicode 方法。

你說:

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.

對於更通用的CharSequence而不是String ,請使用Character.codePointAt

我們可以獲得代碼點編號的 Unicode 名稱。

String name = Character.getName( 97 ) ; // letter `a`

拉丁文小寫字母 A

我們可以得到一個字符串中所有字符的代碼點編號的流。

IntStream codePointsStream = "Cat".codePoints() ;

我們可以把它變成一個Integer對象List 請參閱如何將 Java 8 IntStream 轉換為列表? .

List< Integer > codePointsList = codePointsStream.boxed().collect( Collectors.toList() ) ;

通過調用Character.toString可以將任何代碼點編號更改為單個字符的String

String s = Character.toString( 97 ) ; // 97 is `a`, LATIN SMALL LETTER A. 

一種

我們可以從代碼點編號的IntStream生成一個String對象。 請參閱從代碼點編號的 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`. 

貓🐈


你問:

這是否歸結為您使用的字符編碼?

在內部,Java 中的String始終使用UTF-16

在從 Java 字符串導入或導出文本時,您只能使用其他字符編碼。

所以,回答你的問題,不,字符編碼在這里沒有直接關系。 將文本放入 Java String ,它采用 UTF-16 編碼,因此可以包含任何 Unicode 字符。 當然,要查看該字符,您必須使用帶有為該特定字符定義的字形的字體。

從 Java 字符串導出文本時,如果指定的舊字符編碼無法表示文本中使用的某些 Unicode 字符,則會出現問題。 所以使用現代字符編碼,現在意味着UTF-8因為UTF-16 現在被認為是有害的

這是 Oracle 關於Unicode Character Representations的文檔。 或者,如果您願意,可以在此處查看更詳盡的文檔

char 數據類型(以及 Character 對象封裝的值)基於原始 Unicode 規范,該規范將字符定義為固定寬度的 16 位實體。 Unicode 標准已經更改為允許表示需要超過 16 位的字符。 合法代碼點的范圍現在是 U+0000 到 U+10FFFF,稱為 Unicode 標量值。 (請參閱 Unicode 標准中 U+n 符號的定義。)

從 U+0000 到 U+FFFF 的字符集有時稱為基本多語言平面 (BMP)。 碼位大於 U+FFFF 的字符稱為增補字符。 Java 2 平台在 char 數組以及 String 和 StringBuffer 類中使用 UTF-16 表示。 在這種表示中,增補字符表示為一對字符值,第一個來自高代理范圍 (\?-\?),第二個來自低代理范圍 (\?-\?)。

因此,char 值表示基本多語言平面 (BMP) 代碼點,包括代理代碼點或 UTF-16 編碼的代碼單元。 int 值表示所有 Unicode 代碼點,包括補充代碼點。 int 的低(最低有效)21 位用於表示Unicode 代碼點,高(最高)11 位必須為零。 除非另有說明,關於增補字符和代理字符值的行為如下:

  • 僅接受 char 值的方法不能支持增補字符。 他們將代理范圍中的 char 值視為未定義的字符。 例如, Character.isLetter('\?') 返回 false,即使此特定值后跟字符串中的任何低代理值將表示一個字母。
  • 接受 int 值的方法支持所有 Unicode 字符,包括增補字符。 例如,Character.isLetter(0x2F81A) 返回 true,因為代碼點值表示一個字母(CJK 表意文字)。

查看J2SE 1.5中的Unicode 4.0 支持文章,了解更多有關 Sun 發明的技巧以提供對所有 Unicode 4.0 代碼點的支持。

總之,您會發現 Java 1.5 中 Unicode 4.0 的以下更改:

  • char是一個 UTF-16 代碼單元,而不是一個代碼點
  • 新的低級 API 使用int來表示 Unicode 代碼點
  • 已更新高級 API 以了解代理對
  • 偏好使用字符序列 API 而不是基於字符的方法

由於 Java 沒有 32 位字符,我會讓您判斷我們是否可以稱之為良好的 Unicode 支持。

來自StringOpenJDK7 文檔

字符串表示 UTF-16 格式的字符串,其中補充字符由代理對表示(有關更多信息,請參閱字符類中的 Unicode 字符表示部分)。 索引值指的是字符代碼單元,因此增補字符使用字符串中的兩個位置。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM