字元在內存中最終的表示形式是什麼?是某種字元編碼還是碼位(Code Point)?
根據我的了解,編碼中有三個核心概念:
1. 字符集(Character Set),可以說是一個抽象概念,字元的合集2. 碼位(Code Point),將抽象的字符集中每一個字元映射到一個整數3. 字元編碼(Encoding),按照某種編碼規則用二進位來表示一個字元我對碼位這個概念理解的不是很清楚,Code point中說:
The notion of a code point is used for abstraction, to distinguish both:
- the number from an encoding as a sequence of bits, and
- the abstract character from a particular graphical representation (glyph).
This is because one may wish to make these distinctions:
- encode a particular code space in different ways, or
- display a character via different glyphs.
說Code Point是用於抽象,但Java中依然可以使用codePointAt方法來獲取實際的整數值
String str = "JAVA";
System.out.println("String = " + str);// codepoint at index 1
int retval = str.codePointAt(1);// prints character at index1 in string
用Java的String來舉例子,引用自深入分析 Java 中的中文編碼問題:
System.out.println("Character(unicode point) = " + retval);
String str = 「I am 君山」;
String 內部的char 數組的值為 49 20 61 6d 20 541b 5c71
請問這char數組的值是碼位嗎,還是說是JVM使用的UTF16的編碼?
字元在內存中最終的表示形式是什麼?是不是和具體編程語言相關?
code point是protocol,encoding是內存格式。這就像Unicode與UTF-32的區別一樣。
在現代編碼模型里要知道一個字元如何映射成計算機里比特,需要經過如下幾個步驟。
- 知道一個系統需要支持哪些字元,這些字元的集合被稱為字元表(Character repertoire)
- 給字元表裡的抽象字元編上一個數字,也就是字符集合到一個整數集合的映射。這種映射稱為編碼字符集(CCS:Coded Character Set),unicode是屬於這一層的概念,跟計算機里的什麼進位啊沒有任何關係,它是完全數學的抽象的。
- 將CCS里字元對應的整數轉換成有限長度的比特值,便於以後計算機使用一定長度的二進位形式表示該整數。這個對應關係被稱為字元編碼表(CEF:Character Encoding Form)UTF-8, UTF-16都屬於這層。
- 對於CEF得到的比特值具體如何在計算機中進行存儲,傳輸。因為存在大端小端的問題,這就會跟具體的操作系統相關了。這種解決方案稱為字元編碼方案(CES:Character Encoding Scheme)。
平常我們所說的編碼都在第三步的時候完成了,都沒有涉及到CES。
以上摘自(http://blog.jobbole.com/39309/)
unicode只是一種抽象概念,使用一個數字來表示字符集中的一個字元,相當於規定了unicode字符集中那一百多萬個字元和數字的映射,代碼點就相當於這個字元對應著的數字了。Java中採用UTF-16編碼方式對unicode進行表示(unicode是一種抽象概念,只確定了字元和碼位的映射關係,不管編碼),就是字元串的編碼是utf-16,題主的例子中很清楚了。
注意char類型16位,單個char肯定無法表示這一百多萬個碼位的,一但字元串中出現了char無法表示的碼位(字元)的時候,這時候就用utf-16進行編碼,用多個char表示這個碼位,相應字元串的length方法也比字元要多(length是char數組的長度),用charat方法也不一定能獲得那個字元,而要用codepointat方法獲得那個位置所在的字元的unicode碼位,我記得還有一個codepointsize方法,可以獲得具體的(碼位)字元數。
再次強調一下,這個碼位表示的是一個整數,是unicode編碼里規定的某個字元想對應的整數。
所幸大多數常用字元都能用一個char類型表示,所以一般length方法都能確定字元串中字元的個數,但這個方式看起來不是那麼可靠,所以不是處理英文的地方,算字元數量的時候,還是考慮不要用length了吧。
以上。
手機碼字,求指正錯誤。
感覺題主對字元編碼已經理解的非常清楚了,不過我不知道題主說「我對碼位這個概念理解的不是很清楚」是指哪裡?
關於Java String的內存表示問題,題主說的那個內部char數組是UTF16碼,而不是Unicode Code Point。其實Java裡面的char本來就都是UTF16碼,Unicode Code Point的數字範圍已經超出char類型的範圍了。
字元串對象在內存中的表示形式,不同語言確實有些許差異,不過大致只有兩類:
一類是像C這種比較原始(raw)、比較底層、比較直接的語言,基本就是把你的源文件裡面的那幾個代表字元的位元組原封不動的編譯到可執行文件中,然後載入到內存中。所以這種情況下,字元串對象在內存中的表示形式,直接就是按你源文件的編碼來的。
另一類是像Java、Python3之類的比較高級一點的語言,字元串對象在內存中通常是用UTF16表示的。
不過Python2情況還稍微複雜點,它有兩種字元串對象,一種是UnicodeObject,另一種是StringObject。區別就是前者相當於Java String,後者相當於C char*。
現在C/C++中也有兩種字元類型,一種是傳統的char,另一種是寬字元wchar_t,這個跟Python2的情況比較類似。不過嚴格來說wchar_t的具體寬度是取決於不同編譯器的實現的。GCC的實現貌似是32位,不知道是什麼編碼。VC應該是16位,採用UTF16編碼。https://zhuanlan.zhihu.com/p/26261762
字元在內存里就是一個或若干個byte,但這寫byte表示的含義是由編碼決定的。比如一個byte的值是65,在ascii里表示"A",ascii 有128個碼位,65號是"A"。你有興趣也能自己搞個編碼,只有26個碼位,第0位是"A"。然後提供這種編碼到各種其它編碼的轉換演算法。所謂編碼就是製造一種映射a-&>b
推薦閱讀:
※要往 Unicode 里添加符號需要經過什麼樣的流程?
※給在美國的外國人發郵件,郵件中出現的漢字能正常顯示嗎?
※Microsoft開發記事本的團隊,是不是使用了一個非常弱智的行為來保存UTF-8編碼的文件?
※一個特殊的亂碼問題?
TAG:字元編碼 |