簡體   English   中英

Java - 什么是字符、代碼點和代理? 它們之間有什么區別?

[英]Java - what are characters, code points and surrogates? What difference is there between them?

我試圖找到術語“字符”、“代碼點”和“代理”的解釋,雖然這些術語不限於 Java,但如果有任何特定於語言的差異,我希望解釋為它與Java有關。

我發現了一些關於字符和代碼點之間差異的信息,字符是向人類用戶顯示的內容,代碼點是對特定字符進行編碼的值,但我不知道代理。 什么是代理,它們與字符和代碼點有何不同? 我對字符和代碼點有正確的定義嗎?

另一個關於將字符串作為字符數組單步執行的帖子中,提示這個問題的具體評論是“請注意,此技術為您提供字符,而不是代碼點,這意味着您可能會獲得代理。” 我真的不明白,與其對一個 5 年前的問題發表一長串評論,我認為最好在一個新問題中要求澄清。

要在計算機中表示文本,您必須解決兩件事:首先,您必須將符號映射到數字,然后,您必須用字節表示這些數字的序列。

代碼點是標識符號的數字。 為符號分配數字的兩個眾所周知的標准是 ASCII 和 Unicode。 ASCII 定義了 128 個符號。 Unicode 目前定義了 109384 個符號,比 2 16多得多。

此外,ASCII 指定數字序列每個數字表示一個字節,而 Unicode 指定了幾種可能性,例如 UTF-8、UTF-16 和 UTF-32。

當您嘗試使用每個字符使用的位數少於表示所有可能值所需的位數時(例如使用 16 位的 UTF-16),您需要一些解決方法。

因此, 代理項是 16 位值,表示不適合單個兩字節值的符號。

Java 在內部使用UTF-16來表示文本。

特別是, char (字符)是包含 UTF-16 值的無符號兩字節值。

如果您想了解有關 Java 和 Unicode 的更多信息,我可以推薦此時事通訊:第 1部分第 2 部分

您可以在 Javadoc 中找到java.lang.Character類的簡短說明:

Unicode 字符表示

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

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

換句話說:

代碼點通常表示單個字符 最初, char類型的值與 Unicode 代碼點完全匹配。 這種編碼也被稱為UCS-2

因此, char被定義為 16 位類型。 但是,目前 Unicode 中有超過 2^16 個字符 為了支持整個字符集,編碼從固定長度編碼UCS-2更改為可變長度編碼UTF-16 在這種編碼中,每個代碼點由單個char或兩個char 在后一種情況下,這兩個字符稱為代理對

UTF-16 的定義方式是,如果所有代碼點都低於 2^14,則使用 UTF-16 和 UCS-2 編碼的文本之間沒有區別。 這意味着, char可用於表示某些但不是所有字符 如果一個字符不能在單個char表示,則術語char具有誤導性,因為它僅用作 16 位字。

代碼點通常是指 Unicode 代碼點。 Unicode 詞匯表是這樣說的:

Codepoint(1) : Unicode 代碼空間中的任何值; 即 0 到 10FFFF16 的整數范圍。

在 Java 中,字符 ( char ) 是一個無符號的 16 位值; 即 0 到 FFFF。

如您所見,有更多 Unicode 代碼點可以表示為 Java 字符。 然而,Java 需要能夠使用所有有效的 Unicode 代碼點來表示文本。

Java 處理這種情況的方法是將大於 FFFF 的代碼點表示為一字符(代碼單元); 代理對 這些編碼一個Unicode編碼點比FFFF較大為一對16位值。 這使用了 Unicode 代碼空間的子范圍(即 D800 到 U+DFFF)保留用於表示代理對的事實。 技術細節在這里


Java 使用的編碼的正確術語是UTF-16 Encoding Form

您可能會看到的另一個術語是代碼單元,它是特定編碼中使用的最小表示單元。 在 UTF-16 中,代碼單元是 16 位,對應於 Java char 其他編碼(例如 UTF-8、ISO 8859-1 等)具有 8 位代碼單元,而 UTF-32 具有 32 位代碼單元。


字符這個詞有很多含義。 這意味着在不同的上下文中的各種事物。 Unicode 詞匯表給出了Character 的4 種含義,如下所示:

特點。 (1) 書面語言中具有語義價值的最小成分; 指的是抽象的含義和/或形狀,而不是特定的形狀(另見字形),盡管在代碼表中,某種形式的視覺表示對於讀者的理解是必不可少的。

特點。 (2) 抽象字符的同義詞。 抽象字符。用於組織、控制或表示文本數據的信息單元。)

特點。 (3) Unicode 字符編碼的基本編碼單位。

特點。 (4) 源自中國的表意文字的英文名稱。 [見表意文字 (2)。]

然后是字符的Java特定含義; 即一個 16 位有符號數( char類型),它可能代表也可能不代表 UTF-16 編碼中的完整或部分 Unicode 代碼點。

首先,unicode 是一個標准,它試圖定義和映射所有語言的所有單個字符,從英文字母到中文、數字、符號等。

基本上 unicode 有很長的編號字符列表,其中代碼點是指編號。

簡而言之

  • 字符是文本中的單個標記,無論是字母、數字還是符號。
  • 代碼點是指 unicode 標准中令牌的編號
  • 使用UTF-16編碼方案表示的字符包含如此多的字符,所有字符都無法放入單個 Java 字符的分配空間中。
  • 代理對是用來表示一個字符需要在一對字符的空間中表示的術語。 代理對是一個術語,用來表示一個字符在 unicode 表中列得太高,需要一對字符空格來表示它。

簡單的說:

  • Code unitchar占 2 個字節,編碼為UTF-16 ,每個字符不一定代表real world character
  • Code point始終是real world character ,它可能包含 1 或 2 個Code unit ,將其視為int ,可能需要 4 個字節。

讓代碼(測試用例)說出真相:
(需要 Java 9 +,由於 String 的方法codePoints()chars()

@Test
public void test() {
    String s = "Hi, 你好, おはよう, α-Ω\uD834\uDD1E"; // last real character is "𝄞", that takes 2 code unit,
    assertEquals(s.length(), s.toCharArray().length); // length() is based on char (aka code unit), not code point,

    System.out.printf("input string:\t\"%s\"%n%n", s);

    System.out.println("------ as code point (aka. real character) ------");
    // code point,
    s.codePoints().forEach(cp -> System.out.println(Character.toChars(cp)));
    assertEquals(s.codePoints().count(), s.length() - 1); // last read character takes 2 unit code,
    assertEquals(s.codePoints().count(), s.codePointCount(0, s.length())); // there is a method codePointCount() on String to get code point count on given char range,

    System.out.println("\n------ as char (aka. code unit) ------");
    // chars (aka. code unit),
    s.chars().forEach(c -> System.out.println(Character.toChars(c)));
    assertEquals(s.chars().count(), s.length()); // string length is the count of code unit, not code point,
}

輸出:

input string:   "Hi, 你好, おはよう, α-Ω𝄞"

------ as code point (aka. real character) ------
H
i
,
 
你
好
,
 
お
は
よ
う
,
 
α
-
Ω
𝄞

------ as char (aka. code unit) ------
H
i
,
 
你
好
,
 
お
は
よ
う
,
 
α
-
Ω
?
?

最后一個真正的字符是𝄞 ,它需要 2 個代碼單元\?\? ,它是一個單一的code point ,當嘗試分別打印 2 個代碼單元時,它們無法識別,並顯示? 對於每個。

暫無
暫無

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

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